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.
+
+
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.
+
+
\ 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.
+
+
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.
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.0falsewin-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