Using variables with the same name is dangerous. However, such a situation inside the while loop can create an infinite loop exhausting resources. Requires the attention of developers.
+ +We recommend not to use local variables inside a loop if their names are the same as the variables in the condition of this loop.
+ +The following example demonstrates an erroneous and corrected use of a local variable within a loop.
+Python has been the most widely used programming language in recent years, and Jython + (formerly known as JPython) is a popular Java implementation of Python. It allows + embedded Python scripting inside Java applications and provides an interactive interpreter + that can be used to interact with Java packages or with running Java applications. If an + expression is built using attacker-controlled data and then evaluated, it may allow the + attacker to run arbitrary code.
+In general, including user input in Jython expression should be avoided. If user input + must be included in an expression, it should be then evaluated in a safe context that + doesn't allow arbitrary code invocation.
+The following code could execute arbitrary code in Jython Interpreter
+", 1, null);
+ response.getWriter().print(Context.toString(result));
+ } catch(RhinoException ex) {
+ response.getWriter().println(ex.getMessage());
+ } finally {
+ Context.exit();
+ }
+ }
+}
diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/ScriptEngine.qhelp b/java/ql/src/experimental/Security/CWE/CWE-094/ScriptEngine.qhelp
deleted file mode 100644
index 74159c562c5..00000000000
--- a/java/ql/src/experimental/Security/CWE/CWE-094/ScriptEngine.qhelp
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-The ScriptEngine API has been available since the release of Java 6.
-It allows applications to interact with scripts written in languages such as JavaScript.
-
-
-
-Use "Cloudbees Rhino Sandbox" or sandboxing with SecurityManager or use graalvm instead.
-
-
-
-The following code could execute random JavaScript code
-
-
-
-
-
-
-CERT coding standard: ScriptEngine code injection
-
-
-
diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/ScriptEngine.ql b/java/ql/src/experimental/Security/CWE/CWE-094/ScriptEngine.ql
deleted file mode 100644
index 5e52a61b5c3..00000000000
--- a/java/ql/src/experimental/Security/CWE/CWE-094/ScriptEngine.ql
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * @name ScriptEngine evaluation
- * @description Malicious Javascript code could cause arbitrary command execution at the OS level
- * @kind path-problem
- * @problem.severity error
- * @precision high
- * @id java/unsafe-eval
- * @tags security
- * external/cwe/cwe-094
- */
-
-import java
-import semmle.code.java.dataflow.FlowSources
-import DataFlow::PathGraph
-
-class ScriptEngineMethod extends Method {
- ScriptEngineMethod() {
- this.getDeclaringType().getASupertype*().hasQualifiedName("javax.script", "ScriptEngine") and
- this.hasName("eval")
- }
-}
-
-predicate scriptEngine(MethodAccess ma, Expr sink) {
- exists(Method m | m = ma.getMethod() |
- m instanceof ScriptEngineMethod and
- sink = ma.getArgument(0)
- )
-}
-
-class ScriptEngineSink extends DataFlow::ExprNode {
- ScriptEngineSink() { scriptEngine(_, this.getExpr()) }
-
- MethodAccess getMethodAccess() { scriptEngine(result, this.getExpr()) }
-}
-
-class ScriptEngineConfiguration extends TaintTracking::Configuration {
- ScriptEngineConfiguration() { this = "ScriptEngineConfiguration" }
-
- override predicate isSource(DataFlow::Node source) {
- source instanceof RemoteFlowSource
- or
- source instanceof LocalUserInput
- }
-
- override predicate isSink(DataFlow::Node sink) { sink instanceof ScriptEngineSink }
-}
-
-from DataFlow::PathNode source, DataFlow::PathNode sink, ScriptEngineConfiguration conf
-where conf.hasFlowPath(source, sink)
-select sink.getNode().(ScriptEngineSink).getMethodAccess(), source, sink, "ScriptEngine eval $@.",
- source.getNode(), "user input"
diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/ScriptInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-094/ScriptInjection.qhelp
new file mode 100644
index 00000000000..2683cf9ad29
--- /dev/null
+++ b/java/ql/src/experimental/Security/CWE/CWE-094/ScriptInjection.qhelp
@@ -0,0 +1,52 @@
+
+
+
+
+The Java Scripting API has been available since the release of Java 6. It allows
+ applications to interact with scripts written in languages such as JavaScript. It serves
+ as an embedded scripting engine inside Java applications which allows Java-to-JavaScript
+ interoperability and provides a seamless integration between the two languages. If an
+ expression is built using attacker-controlled data, and then evaluated in a powerful
+ context, it may allow the attacker to run arbitrary code.
+
+
+
+In general, including user input in a Java Script Engine expression should be avoided.
+ If user input must be included in the expression, it should be then evaluated in a safe
+ context that doesn't allow arbitrary code invocation. Use "Cloudbees Rhino Sandbox" or
+ sandboxing with SecurityManager, which will be deprecated in a future release, or use
+ GraalVM instead.
+
+
+
+The following code could execute user-supplied JavaScript code in ScriptEngine
+
+
+
+The following example shows two ways of using Rhino expression. In the 'BAD' case,
+ an unsafe context is initialized with initStandardObjects that allows arbitrary
+ Java code to be executed. In the 'GOOD' case, a safe context is initialized with
+ initSafeStandardObjects or setClassShutter.
+
+
+
+
+
+CERT coding standard: ScriptEngine code injection
+
+
+GraalVM: Secure by Default
+
+
+ Mozilla Rhino: Rhino: JavaScript in Java
+
+
+ Rhino Sandbox: A sandbox to execute JavaScript code with Rhino in Java
+
+
+ GuardRails: Code Injection
+
+
+
diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/ScriptInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-094/ScriptInjection.ql
new file mode 100644
index 00000000000..fb8bf867501
--- /dev/null
+++ b/java/ql/src/experimental/Security/CWE/CWE-094/ScriptInjection.ql
@@ -0,0 +1,146 @@
+/**
+ * @name Injection in Java Script Engine
+ * @description Evaluation of user-controlled data using the Java Script Engine may
+ * lead to remote code execution.
+ * @kind path-problem
+ * @problem.severity error
+ * @precision high
+ * @id java/unsafe-eval
+ * @tags security
+ * external/cwe/cwe-094
+ */
+
+import java
+import semmle.code.java.dataflow.FlowSources
+import DataFlow::PathGraph
+
+/** A method of ScriptEngine that allows code injection. */
+class ScriptEngineMethod extends Method {
+ ScriptEngineMethod() {
+ this.getDeclaringType().getASupertype*().hasQualifiedName("javax.script", "ScriptEngine") and
+ this.hasName("eval")
+ or
+ this.getDeclaringType().getASupertype*().hasQualifiedName("javax.script", "Compilable") and
+ this.hasName("compile")
+ or
+ this.getDeclaringType().getASupertype*().hasQualifiedName("javax.script", "ScriptEngineFactory") and
+ this.hasName(["getProgram", "getMethodCallSyntax"])
+ }
+}
+
+/** The context class `org.mozilla.javascript.Context` of Rhino Java Script Engine. */
+class RhinoContext extends RefType {
+ RhinoContext() { this.hasQualifiedName("org.mozilla.javascript", "Context") }
+}
+
+/** A method that evaluates a Rhino expression with `org.mozilla.javascript.Context`. */
+class RhinoEvaluateExpressionMethod extends Method {
+ RhinoEvaluateExpressionMethod() {
+ this.getDeclaringType().getAnAncestor*() instanceof RhinoContext and
+ this.hasName([
+ "evaluateString", "evaluateReader", "compileFunction", "compileReader", "compileString"
+ ])
+ }
+}
+
+/**
+ * A method that compiles a Rhino expression with
+ * `org.mozilla.javascript.optimizer.ClassCompiler`.
+ */
+class RhinoCompileClassMethod extends Method {
+ RhinoCompileClassMethod() {
+ this.getDeclaringType()
+ .getASupertype*()
+ .hasQualifiedName("org.mozilla.javascript.optimizer", "ClassCompiler") and
+ this.hasName("compileToClassFiles")
+ }
+}
+
+/**
+ * A method that defines a Java class from a Rhino expression with
+ * `org.mozilla.javascript.GeneratedClassLoader`.
+ */
+class RhinoDefineClassMethod extends Method {
+ RhinoDefineClassMethod() {
+ this.getDeclaringType()
+ .getASupertype*()
+ .hasQualifiedName("org.mozilla.javascript", "GeneratedClassLoader") and
+ this.hasName("defineClass")
+ }
+}
+
+/**
+ * Holds if `ma` is a call to a `ScriptEngineMethod` and `sink` is an argument that
+ * will be executed.
+ */
+predicate isScriptArgument(MethodAccess ma, Expr sink) {
+ exists(ScriptEngineMethod m |
+ m = ma.getMethod() and
+ if m.getDeclaringType().getASupertype*().hasQualifiedName("javax.script", "ScriptEngineFactory")
+ then sink = ma.getArgument(_) // all arguments allow script injection
+ else sink = ma.getArgument(0)
+ )
+}
+
+/**
+ * Holds if a Rhino expression evaluation method is vulnerable to code injection.
+ */
+predicate evaluatesRhinoExpression(MethodAccess ma, Expr sink) {
+ exists(RhinoEvaluateExpressionMethod m | m = ma.getMethod() |
+ (
+ if ma.getMethod().getName() = "compileReader"
+ then sink = ma.getArgument(0) // The first argument is the input reader
+ else sink = ma.getArgument(1) // The second argument is the JavaScript or Java input
+ ) and
+ not exists(MethodAccess ca |
+ ca.getMethod().hasName(["initSafeStandardObjects", "setClassShutter"]) and // safe mode or `ClassShutter` constraint is enforced
+ ma.getQualifier() = ca.getQualifier().(VarAccess).getVariable().getAnAccess()
+ )
+ )
+}
+
+/**
+ * Holds if a Rhino expression compilation method is vulnerable to code injection.
+ */
+predicate compilesScript(MethodAccess ma, Expr sink) {
+ exists(RhinoCompileClassMethod m | m = ma.getMethod() | sink = ma.getArgument(0))
+}
+
+/**
+ * Holds if a Rhino class loading method is vulnerable to code injection.
+ */
+predicate definesRhinoClass(MethodAccess ma, Expr sink) {
+ exists(RhinoDefineClassMethod m | m = ma.getMethod() | sink = ma.getArgument(1))
+}
+
+/** A script injection sink. */
+class ScriptInjectionSink extends DataFlow::ExprNode {
+ MethodAccess methodAccess;
+
+ ScriptInjectionSink() {
+ isScriptArgument(methodAccess, this.getExpr()) or
+ evaluatesRhinoExpression(methodAccess, this.getExpr()) or
+ compilesScript(methodAccess, this.getExpr()) or
+ definesRhinoClass(methodAccess, this.getExpr())
+ }
+
+ /** An access to the method associated with this sink. */
+ MethodAccess getMethodAccess() { result = methodAccess }
+}
+
+/**
+ * A taint tracking configuration that tracks flow from `RemoteFlowSource` to an argument
+ * of a method call that executes injected script.
+ */
+class ScriptInjectionConfiguration extends TaintTracking::Configuration {
+ ScriptInjectionConfiguration() { this = "ScriptInjectionConfiguration" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof ScriptInjectionSink }
+}
+
+from DataFlow::PathNode source, DataFlow::PathNode sink, ScriptInjectionConfiguration conf
+where conf.hasFlowPath(source, sink)
+select sink.getNode().(ScriptInjectionSink).getMethodAccess(), source, sink,
+ "Java Script Engine evaluate $@.", source.getNode(), "user input"
diff --git a/java/ql/src/experimental/Security/CWE/CWE-601/SpringUrlRedirect.java b/java/ql/src/experimental/Security/CWE/CWE-601/SpringUrlRedirect.java
new file mode 100644
index 00000000000..eba64aab6a8
--- /dev/null
+++ b/java/ql/src/experimental/Security/CWE/CWE-601/SpringUrlRedirect.java
@@ -0,0 +1,46 @@
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.view.RedirectView;
+
+@Controller
+public class SpringUrlRedirect {
+
+ private final static String VALID_REDIRECT = "http://127.0.0.1";
+
+ @GetMapping("url1")
+ public RedirectView bad1(String redirectUrl, HttpServletResponse response) throws Exception {
+ RedirectView rv = new RedirectView();
+ rv.setUrl(redirectUrl);
+ return rv;
+ }
+
+ @GetMapping("url2")
+ public String bad2(String redirectUrl) {
+ String url = "redirect:" + redirectUrl;
+ return url;
+ }
+
+ @GetMapping("url3")
+ public RedirectView bad3(String redirectUrl) {
+ RedirectView rv = new RedirectView(redirectUrl);
+ return rv;
+ }
+
+ @GetMapping("url4")
+ public ModelAndView bad4(String redirectUrl) {
+ return new ModelAndView("redirect:" + redirectUrl);
+ }
+
+ @GetMapping("url5")
+ public RedirectView good1(String redirectUrl) {
+ RedirectView rv = new RedirectView();
+ if (redirectUrl.startsWith(VALID_REDIRECT)){
+ rv.setUrl(redirectUrl);
+ }else {
+ rv.setUrl(VALID_REDIRECT);
+ }
+ return rv;
+ }
+}
diff --git a/java/ql/src/experimental/Security/CWE/CWE-601/SpringUrlRedirect.qhelp b/java/ql/src/experimental/Security/CWE/CWE-601/SpringUrlRedirect.qhelp
new file mode 100644
index 00000000000..6fe70dfb113
--- /dev/null
+++ b/java/ql/src/experimental/Security/CWE/CWE-601/SpringUrlRedirect.qhelp
@@ -0,0 +1,37 @@
+
+
+
+
+
+Directly incorporating user input into a URL redirect request without validating the input
+can facilitate phishing attacks. In these attacks, unsuspecting users can be redirected to a
+malicious site that looks very similar to the real site they intend to visit, but which is
+controlled by the attacker.
+
+
+
+
+To guard against untrusted URL redirection, it is advisable to avoid putting user input
+directly into a redirect URL. Instead, maintain a list of authorized
+redirects on the server; then choose from that list based on the user input provided.
+
+
+
+
+The following examples show the bad case and the good case respectively.
+In bad1 method and bad2 method and bad3 method and
+bad4 method, shows an HTTP request parameter being used directly in a URL redirect
+without validating the input, which facilitates phishing attacks. In good1 method,
+shows how to solve this problem by verifying whether the user input is a known fixed string beginning.
+
+
+
+
+
+
+A Guide To Spring Redirects: Spring Redirects.
+Url redirection - attack and defense: Url Redirection.
+
+
diff --git a/java/ql/src/experimental/Security/CWE/CWE-601/SpringUrlRedirect.ql b/java/ql/src/experimental/Security/CWE/CWE-601/SpringUrlRedirect.ql
new file mode 100644
index 00000000000..b02bd3e4c30
--- /dev/null
+++ b/java/ql/src/experimental/Security/CWE/CWE-601/SpringUrlRedirect.ql
@@ -0,0 +1,66 @@
+/**
+ * @name Spring url redirection from remote source
+ * @description Spring url redirection based on unvalidated user-input
+ * may cause redirection to malicious web sites.
+ * @kind path-problem
+ * @problem.severity error
+ * @precision high
+ * @id java/spring-unvalidated-url-redirection
+ * @tags security
+ * external/cwe-601
+ */
+
+import java
+import SpringUrlRedirect
+import semmle.code.java.dataflow.FlowSources
+import DataFlow::PathGraph
+
+private class StartsWithSanitizer extends DataFlow::BarrierGuard {
+ StartsWithSanitizer() {
+ this.(MethodAccess).getMethod().hasName("startsWith") and
+ this.(MethodAccess).getMethod().getDeclaringType() instanceof TypeString and
+ this.(MethodAccess).getMethod().getNumberOfParameters() = 1
+ }
+
+ override predicate checks(Expr e, boolean branch) {
+ e = this.(MethodAccess).getQualifier() and branch = true
+ }
+}
+
+class SpringUrlRedirectFlowConfig extends TaintTracking::Configuration {
+ SpringUrlRedirectFlowConfig() { this = "SpringUrlRedirectFlowConfig" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof SpringUrlRedirectSink }
+
+ override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
+ guard instanceof StartsWithSanitizer
+ }
+
+ override predicate isSanitizer(DataFlow::Node node) {
+ // Exclude the case where the left side of the concatenated string is not `redirect:`.
+ // E.g: `String url = "/path?token=" + request.getParameter("token");`
+ // Note this is quite a broad sanitizer (it will also sanitize the right-hand side of `url = "http://" + request.getParameter("token")`);
+ // Consider making this stricter in future.
+ exists(AddExpr ae |
+ ae.getRightOperand() = node.asExpr() and
+ not ae instanceof RedirectBuilderExpr
+ )
+ or
+ exists(MethodAccess ma, int index |
+ ma.getMethod().hasName("format") and
+ ma.getMethod().getDeclaringType() instanceof TypeString and
+ ma.getArgument(index) = node.asExpr() and
+ (
+ index != 0 and
+ not ma.getArgument(0).(CompileTimeConstantExpr).getStringValue().regexpMatch("^%s.*")
+ )
+ )
+ }
+}
+
+from DataFlow::PathNode source, DataFlow::PathNode sink, SpringUrlRedirectFlowConfig conf
+where conf.hasFlowPath(source, sink)
+select sink.getNode(), source, sink, "Potentially untrusted URL redirection due to $@.",
+ source.getNode(), "user-provided value"
diff --git a/java/ql/src/experimental/Security/CWE/CWE-601/SpringUrlRedirect.qll b/java/ql/src/experimental/Security/CWE/CWE-601/SpringUrlRedirect.qll
new file mode 100644
index 00000000000..4a86640d4d4
--- /dev/null
+++ b/java/ql/src/experimental/Security/CWE/CWE-601/SpringUrlRedirect.qll
@@ -0,0 +1,73 @@
+import java
+import DataFlow
+import semmle.code.java.dataflow.FlowSources
+import semmle.code.java.dataflow.DataFlow2
+import semmle.code.java.dataflow.TaintTracking
+import semmle.code.java.frameworks.spring.SpringController
+
+/**
+ * A concatenate expression using the string `redirect:` or `ajaxredirect:` or `forward:` on the left.
+ *
+ * E.g: `"redirect:" + redirectUrl`
+ */
+class RedirectBuilderExpr extends AddExpr {
+ RedirectBuilderExpr() {
+ this.getLeftOperand().(CompileTimeConstantExpr).getStringValue() in [
+ "redirect:", "ajaxredirect:", "forward:"
+ ]
+ }
+}
+
+/**
+ * A call to `StringBuilder.append` or `StringBuffer.append` method, and the parameter value is
+ * `"redirect:"` or `"ajaxredirect:"` or `"forward:"`.
+ *
+ * E.g: `StringBuilder.append("redirect:")`
+ */
+class RedirectAppendCall extends MethodAccess {
+ RedirectAppendCall() {
+ this.getMethod().hasName("append") and
+ this.getMethod().getDeclaringType() instanceof StringBuildingType and
+ this.getArgument(0).(CompileTimeConstantExpr).getStringValue() in [
+ "redirect:", "ajaxredirect:", "forward:"
+ ]
+ }
+}
+
+/** A URL redirection sink from spring controller method. */
+class SpringUrlRedirectSink extends DataFlow::Node {
+ SpringUrlRedirectSink() {
+ exists(RedirectBuilderExpr rbe |
+ rbe.getRightOperand() = this.asExpr() and
+ any(SpringRequestMappingMethod sqmm).polyCalls*(this.getEnclosingCallable())
+ )
+ or
+ exists(MethodAccess ma, RedirectAppendCall rac |
+ DataFlow2::localExprFlow(rac.getQualifier(), ma.getQualifier()) and
+ ma.getMethod().hasName("append") and
+ ma.getArgument(0) = this.asExpr() and
+ any(SpringRequestMappingMethod sqmm).polyCalls*(this.getEnclosingCallable())
+ )
+ or
+ exists(MethodAccess ma |
+ ma.getMethod().hasName("setUrl") and
+ ma.getMethod()
+ .getDeclaringType()
+ .hasQualifiedName("org.springframework.web.servlet.view", "AbstractUrlBasedView") and
+ ma.getArgument(0) = this.asExpr()
+ )
+ or
+ exists(ClassInstanceExpr cie |
+ cie.getConstructedType()
+ .hasQualifiedName("org.springframework.web.servlet.view", "RedirectView") and
+ cie.getArgument(0) = this.asExpr()
+ )
+ or
+ exists(ClassInstanceExpr cie |
+ cie.getConstructedType().hasQualifiedName("org.springframework.web.servlet", "ModelAndView") and
+ exists(RedirectBuilderExpr rbe |
+ rbe = cie.getArgument(0) and rbe.getRightOperand() = this.asExpr()
+ )
+ )
+ }
+}
diff --git a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll
index fee40a328a1..5e4a307002a 100644
--- a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll
+++ b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll
@@ -77,6 +77,7 @@ private module Frameworks {
private import semmle.code.java.frameworks.ApacheHttp
private import semmle.code.java.frameworks.apache.Lang
private import semmle.code.java.frameworks.guava.Guava
+ private import semmle.code.java.frameworks.jackson.JacksonSerializability
private import semmle.code.java.security.ResponseSplitting
private import semmle.code.java.security.XSS
private import semmle.code.java.security.LdapInjection
@@ -293,6 +294,7 @@ private predicate summaryModelCsv(string row) {
"java.util;StringTokenizer;false;StringTokenizer;;;Argument[0];Argument[-1];taint",
"java.beans;XMLDecoder;false;XMLDecoder;;;Argument[0];Argument[-1];taint",
"com.esotericsoftware.kryo.io;Input;false;Input;;;Argument[0];Argument[-1];taint",
+ "com.esotericsoftware.kryo5.io;Input;false;Input;;;Argument[0];Argument[-1];taint",
"java.io;BufferedInputStream;false;BufferedInputStream;;;Argument[0];Argument[-1];taint",
"java.io;DataInputStream;false;DataInputStream;;;Argument[0];Argument[-1];taint",
"java.io;ByteArrayInputStream;false;ByteArrayInputStream;;;Argument[0];Argument[-1];taint",
diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll
index 9498e51e7e6..058d66b1496 100644
--- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll
+++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll
@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`.
*/
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
- (
- simpleLocalFlowStep(node1, node2) or
- reverseStepThroughInputOutputAlias(node1, node2)
- ) and
+ simpleLocalFlowStepExt(node1, node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
private predicate jumpStep(Node node1, Node node2, Configuration config) {
- jumpStep(node1, node2) and
+ jumpStepCached(node1, node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg)
)
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
- DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
+ DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) {
viableParamArg(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
- private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
- ) {
- exists(ParameterNode p |
+ private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
+ exists(ParamNode p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
- private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
+ private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
- DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
+ DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
+ DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
- DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/
private class FlowCheckNode extends Node {
FlowCheckNode() {
- this instanceof CastNode or
- clearsContent(this, _)
+ castNode(this) or
+ clearsContentCached(this, _)
}
}
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
- node instanceof ParameterNode or
+ node instanceof ParamNode or
node instanceof OutNodeExt or
store(_, _, node, _) or
read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
- not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
- t = getNodeType(node1)
+ t = getNodeDataFlowType(node1)
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
- t = getNodeType(node2)
+ t = getNodeDataFlowType(node2)
) and
node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and
- not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
- t = getNodeType(node2) and
+ t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
+ PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
}
bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap]
private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and
- if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
+ if node instanceof CastingNode
+ then compatibleTypes(getNodeDataFlowType(node), ap.getType())
+ else any()
}
bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
+ PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
}
bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
- DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx =
TSummaryCtxNone() or
- TSummaryCtxSome(ParameterNode p, AccessPath ap) {
+ TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
- private ParameterNode p;
+ private ParamNode p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
- ap = TAccessPathNil(getNodeType(node))
+ ap = TAccessPathNil(getNodeDataFlowType(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() }
private predicate isHidden() {
- nodeIsHidden(this.getNode()) and
+ hiddenNode(this.getNode()) and
not this.isSource() and
not this instanceof PathNodeSink
}
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
- ap = TAccessPathNil(getNodeType(node))
+ ap = TAccessPathNil(getNodeDataFlowType(node))
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
arg = mid.getNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
- PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
+ PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
- TSummaryCtx1Param(ParameterNode p)
+ TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
- not clearsContent(node, ap.getHead()) and
+ not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
)
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
- not clearsContent(node, ap.getHead().getContent()) and
+ not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode
- then compatibleTypes(getNodeType(node), ap.getType())
+ then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
)
}
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
(
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration()
)
or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and
- compatibleTypes(ap.getType(), getNodeType(node))
+ compatibleTypes(ap.getType(), getNodeDataFlowType(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
arg = mid.getNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
- PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
+ PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
- exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
+ exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
- exists(ParameterNode p |
+ exists(ParamNode p |
mid.getNode() = p and
viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
- exists(PartialPathNodeRev mid, ParameterNode p |
+ exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and
p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
- PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
+ PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll
index 9498e51e7e6..058d66b1496 100644
--- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll
+++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll
@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`.
*/
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
- (
- simpleLocalFlowStep(node1, node2) or
- reverseStepThroughInputOutputAlias(node1, node2)
- ) and
+ simpleLocalFlowStepExt(node1, node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
private predicate jumpStep(Node node1, Node node2, Configuration config) {
- jumpStep(node1, node2) and
+ jumpStepCached(node1, node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg)
)
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
- DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
+ DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) {
viableParamArg(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
- private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
- ) {
- exists(ParameterNode p |
+ private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
+ exists(ParamNode p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
- private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
+ private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
- DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
+ DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
+ DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
- DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/
private class FlowCheckNode extends Node {
FlowCheckNode() {
- this instanceof CastNode or
- clearsContent(this, _)
+ castNode(this) or
+ clearsContentCached(this, _)
}
}
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
- node instanceof ParameterNode or
+ node instanceof ParamNode or
node instanceof OutNodeExt or
store(_, _, node, _) or
read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
- not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
- t = getNodeType(node1)
+ t = getNodeDataFlowType(node1)
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
- t = getNodeType(node2)
+ t = getNodeDataFlowType(node2)
) and
node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and
- not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
- t = getNodeType(node2) and
+ t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
+ PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
}
bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap]
private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and
- if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
+ if node instanceof CastingNode
+ then compatibleTypes(getNodeDataFlowType(node), ap.getType())
+ else any()
}
bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
+ PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
}
bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
- DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx =
TSummaryCtxNone() or
- TSummaryCtxSome(ParameterNode p, AccessPath ap) {
+ TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
- private ParameterNode p;
+ private ParamNode p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
- ap = TAccessPathNil(getNodeType(node))
+ ap = TAccessPathNil(getNodeDataFlowType(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() }
private predicate isHidden() {
- nodeIsHidden(this.getNode()) and
+ hiddenNode(this.getNode()) and
not this.isSource() and
not this instanceof PathNodeSink
}
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
- ap = TAccessPathNil(getNodeType(node))
+ ap = TAccessPathNil(getNodeDataFlowType(node))
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
arg = mid.getNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
- PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
+ PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
- TSummaryCtx1Param(ParameterNode p)
+ TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
- not clearsContent(node, ap.getHead()) and
+ not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
)
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
- not clearsContent(node, ap.getHead().getContent()) and
+ not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode
- then compatibleTypes(getNodeType(node), ap.getType())
+ then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
)
}
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
(
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration()
)
or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and
- compatibleTypes(ap.getType(), getNodeType(node))
+ compatibleTypes(ap.getType(), getNodeDataFlowType(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
arg = mid.getNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
- PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
+ PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
- exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
+ exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
- exists(ParameterNode p |
+ exists(ParamNode p |
mid.getNode() = p and
viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
- exists(PartialPathNodeRev mid, ParameterNode p |
+ exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and
p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
- PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
+ PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll
index 9498e51e7e6..058d66b1496 100644
--- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll
+++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll
@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`.
*/
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
- (
- simpleLocalFlowStep(node1, node2) or
- reverseStepThroughInputOutputAlias(node1, node2)
- ) and
+ simpleLocalFlowStepExt(node1, node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
private predicate jumpStep(Node node1, Node node2, Configuration config) {
- jumpStep(node1, node2) and
+ jumpStepCached(node1, node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg)
)
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
- DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
+ DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) {
viableParamArg(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
- private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
- ) {
- exists(ParameterNode p |
+ private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
+ exists(ParamNode p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
- private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
+ private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
- DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
+ DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
+ DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
- DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/
private class FlowCheckNode extends Node {
FlowCheckNode() {
- this instanceof CastNode or
- clearsContent(this, _)
+ castNode(this) or
+ clearsContentCached(this, _)
}
}
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
- node instanceof ParameterNode or
+ node instanceof ParamNode or
node instanceof OutNodeExt or
store(_, _, node, _) or
read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
- not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
- t = getNodeType(node1)
+ t = getNodeDataFlowType(node1)
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
- t = getNodeType(node2)
+ t = getNodeDataFlowType(node2)
) and
node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and
- not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
- t = getNodeType(node2) and
+ t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
+ PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
}
bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap]
private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and
- if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
+ if node instanceof CastingNode
+ then compatibleTypes(getNodeDataFlowType(node), ap.getType())
+ else any()
}
bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
+ PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
}
bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
- DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx =
TSummaryCtxNone() or
- TSummaryCtxSome(ParameterNode p, AccessPath ap) {
+ TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
- private ParameterNode p;
+ private ParamNode p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
- ap = TAccessPathNil(getNodeType(node))
+ ap = TAccessPathNil(getNodeDataFlowType(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() }
private predicate isHidden() {
- nodeIsHidden(this.getNode()) and
+ hiddenNode(this.getNode()) and
not this.isSource() and
not this instanceof PathNodeSink
}
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
- ap = TAccessPathNil(getNodeType(node))
+ ap = TAccessPathNil(getNodeDataFlowType(node))
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
arg = mid.getNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
- PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
+ PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
- TSummaryCtx1Param(ParameterNode p)
+ TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
- not clearsContent(node, ap.getHead()) and
+ not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
)
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
- not clearsContent(node, ap.getHead().getContent()) and
+ not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode
- then compatibleTypes(getNodeType(node), ap.getType())
+ then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
)
}
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
(
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration()
)
or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and
- compatibleTypes(ap.getType(), getNodeType(node))
+ compatibleTypes(ap.getType(), getNodeDataFlowType(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
arg = mid.getNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
- PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
+ PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
- exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
+ exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
- exists(ParameterNode p |
+ exists(ParamNode p |
mid.getNode() = p and
viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
- exists(PartialPathNodeRev mid, ParameterNode p |
+ exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and
p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
- PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
+ PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll
index 9498e51e7e6..058d66b1496 100644
--- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll
+++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll
@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`.
*/
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
- (
- simpleLocalFlowStep(node1, node2) or
- reverseStepThroughInputOutputAlias(node1, node2)
- ) and
+ simpleLocalFlowStepExt(node1, node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
private predicate jumpStep(Node node1, Node node2, Configuration config) {
- jumpStep(node1, node2) and
+ jumpStepCached(node1, node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg)
)
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
- DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
+ DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) {
viableParamArg(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
- private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
- ) {
- exists(ParameterNode p |
+ private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
+ exists(ParamNode p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
- private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
+ private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
- DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
+ DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
+ DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
- DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/
private class FlowCheckNode extends Node {
FlowCheckNode() {
- this instanceof CastNode or
- clearsContent(this, _)
+ castNode(this) or
+ clearsContentCached(this, _)
}
}
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
- node instanceof ParameterNode or
+ node instanceof ParamNode or
node instanceof OutNodeExt or
store(_, _, node, _) or
read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
- not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
- t = getNodeType(node1)
+ t = getNodeDataFlowType(node1)
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
- t = getNodeType(node2)
+ t = getNodeDataFlowType(node2)
) and
node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and
- not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
- t = getNodeType(node2) and
+ t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
+ PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
}
bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap]
private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and
- if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
+ if node instanceof CastingNode
+ then compatibleTypes(getNodeDataFlowType(node), ap.getType())
+ else any()
}
bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
+ PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
}
bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
- DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx =
TSummaryCtxNone() or
- TSummaryCtxSome(ParameterNode p, AccessPath ap) {
+ TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
- private ParameterNode p;
+ private ParamNode p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
- ap = TAccessPathNil(getNodeType(node))
+ ap = TAccessPathNil(getNodeDataFlowType(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() }
private predicate isHidden() {
- nodeIsHidden(this.getNode()) and
+ hiddenNode(this.getNode()) and
not this.isSource() and
not this instanceof PathNodeSink
}
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
- ap = TAccessPathNil(getNodeType(node))
+ ap = TAccessPathNil(getNodeDataFlowType(node))
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
arg = mid.getNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
- PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
+ PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
- TSummaryCtx1Param(ParameterNode p)
+ TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
- not clearsContent(node, ap.getHead()) and
+ not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
)
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
- not clearsContent(node, ap.getHead().getContent()) and
+ not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode
- then compatibleTypes(getNodeType(node), ap.getType())
+ then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
)
}
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
(
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration()
)
or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and
- compatibleTypes(ap.getType(), getNodeType(node))
+ compatibleTypes(ap.getType(), getNodeDataFlowType(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
arg = mid.getNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
- PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
+ PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
- exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
+ exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
- exists(ParameterNode p |
+ exists(ParamNode p |
mid.getNode() = p and
viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
- exists(PartialPathNodeRev mid, ParameterNode p |
+ exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and
p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
- PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
+ PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll
index 9498e51e7e6..058d66b1496 100644
--- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll
+++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll
@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`.
*/
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
- (
- simpleLocalFlowStep(node1, node2) or
- reverseStepThroughInputOutputAlias(node1, node2)
- ) and
+ simpleLocalFlowStepExt(node1, node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
private predicate jumpStep(Node node1, Node node2, Configuration config) {
- jumpStep(node1, node2) and
+ jumpStepCached(node1, node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg)
)
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
- DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
+ DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) {
viableParamArg(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
- private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
- ) {
- exists(ParameterNode p |
+ private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
+ exists(ParamNode p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
- private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
+ private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
- DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
+ DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
+ DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
- DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/
private class FlowCheckNode extends Node {
FlowCheckNode() {
- this instanceof CastNode or
- clearsContent(this, _)
+ castNode(this) or
+ clearsContentCached(this, _)
}
}
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
- node instanceof ParameterNode or
+ node instanceof ParamNode or
node instanceof OutNodeExt or
store(_, _, node, _) or
read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
- not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
- t = getNodeType(node1)
+ t = getNodeDataFlowType(node1)
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
- t = getNodeType(node2)
+ t = getNodeDataFlowType(node2)
) and
node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and
- not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
- t = getNodeType(node2) and
+ t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
+ PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
}
bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap]
private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and
- if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
+ if node instanceof CastingNode
+ then compatibleTypes(getNodeDataFlowType(node), ap.getType())
+ else any()
}
bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
+ PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
}
bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
- DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx =
TSummaryCtxNone() or
- TSummaryCtxSome(ParameterNode p, AccessPath ap) {
+ TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
- private ParameterNode p;
+ private ParamNode p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
- ap = TAccessPathNil(getNodeType(node))
+ ap = TAccessPathNil(getNodeDataFlowType(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() }
private predicate isHidden() {
- nodeIsHidden(this.getNode()) and
+ hiddenNode(this.getNode()) and
not this.isSource() and
not this instanceof PathNodeSink
}
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
- ap = TAccessPathNil(getNodeType(node))
+ ap = TAccessPathNil(getNodeDataFlowType(node))
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
arg = mid.getNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
- PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
+ PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
- TSummaryCtx1Param(ParameterNode p)
+ TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
- not clearsContent(node, ap.getHead()) and
+ not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
)
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
- not clearsContent(node, ap.getHead().getContent()) and
+ not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode
- then compatibleTypes(getNodeType(node), ap.getType())
+ then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
)
}
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
(
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration()
)
or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and
- compatibleTypes(ap.getType(), getNodeType(node))
+ compatibleTypes(ap.getType(), getNodeDataFlowType(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
arg = mid.getNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
- PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
+ PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
- exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
+ exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
- exists(ParameterNode p |
+ exists(ParamNode p |
mid.getNode() = p and
viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
- exists(PartialPathNodeRev mid, ParameterNode p |
+ exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and
p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
- PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
+ PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl6.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl6.qll
index 9498e51e7e6..058d66b1496 100644
--- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl6.qll
+++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl6.qll
@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`.
*/
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
- (
- simpleLocalFlowStep(node1, node2) or
- reverseStepThroughInputOutputAlias(node1, node2)
- ) and
+ simpleLocalFlowStepExt(node1, node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
private predicate jumpStep(Node node1, Node node2, Configuration config) {
- jumpStep(node1, node2) and
+ jumpStepCached(node1, node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg)
)
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
- DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
+ DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) {
viableParamArg(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
- private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
- ) {
- exists(ParameterNode p |
+ private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
+ exists(ParamNode p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
- private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
+ private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
- DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
+ DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
+ DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
- DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/
private class FlowCheckNode extends Node {
FlowCheckNode() {
- this instanceof CastNode or
- clearsContent(this, _)
+ castNode(this) or
+ clearsContentCached(this, _)
}
}
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
- node instanceof ParameterNode or
+ node instanceof ParamNode or
node instanceof OutNodeExt or
store(_, _, node, _) or
read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
- not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
- t = getNodeType(node1)
+ t = getNodeDataFlowType(node1)
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
- t = getNodeType(node2)
+ t = getNodeDataFlowType(node2)
) and
node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and
- not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
- t = getNodeType(node2) and
+ t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
+ PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
}
bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap]
private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and
- if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
+ if node instanceof CastingNode
+ then compatibleTypes(getNodeDataFlowType(node), ap.getType())
+ else any()
}
bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
+ PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
}
bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
- DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx =
TSummaryCtxNone() or
- TSummaryCtxSome(ParameterNode p, AccessPath ap) {
+ TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
- private ParameterNode p;
+ private ParamNode p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
- ap = TAccessPathNil(getNodeType(node))
+ ap = TAccessPathNil(getNodeDataFlowType(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() }
private predicate isHidden() {
- nodeIsHidden(this.getNode()) and
+ hiddenNode(this.getNode()) and
not this.isSource() and
not this instanceof PathNodeSink
}
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
- ap = TAccessPathNil(getNodeType(node))
+ ap = TAccessPathNil(getNodeDataFlowType(node))
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
arg = mid.getNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
- PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
+ PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
- TSummaryCtx1Param(ParameterNode p)
+ TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
- not clearsContent(node, ap.getHead()) and
+ not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
)
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
- not clearsContent(node, ap.getHead().getContent()) and
+ not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode
- then compatibleTypes(getNodeType(node), ap.getType())
+ then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
)
}
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
(
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration()
)
or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and
- compatibleTypes(ap.getType(), getNodeType(node))
+ compatibleTypes(ap.getType(), getNodeDataFlowType(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
arg = mid.getNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
- PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
+ PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
- exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
+ exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
- exists(ParameterNode p |
+ exists(ParamNode p |
mid.getNode() = p and
viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
- exists(PartialPathNodeRev mid, ParameterNode p |
+ exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and
p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
- PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
+ PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll
index 966c30038cc..462e89ac9ed 100644
--- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll
+++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll
@@ -35,22 +35,22 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
*/
private module LambdaFlow {
- private predicate viableParamNonLambda(DataFlowCall call, int i, ParameterNode p) {
+ private predicate viableParamNonLambda(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallable(call), i)
}
- private predicate viableParamLambda(DataFlowCall call, int i, ParameterNode p) {
+ private predicate viableParamLambda(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallableLambda(call, _), i)
}
- private predicate viableParamArgNonLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
+ private predicate viableParamArgNonLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i |
viableParamNonLambda(call, i, p) and
arg.argumentOf(call, i)
)
}
- private predicate viableParamArgLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
+ private predicate viableParamArgLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i |
viableParamLambda(call, i, p) and
arg.argumentOf(call, i)
@@ -118,8 +118,8 @@ private module LambdaFlow {
boolean toJump, DataFlowCallOption lastCall
) {
revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and
- if node instanceof CastNode or node instanceof ArgumentNode or node instanceof ReturnNode
- then compatibleTypes(t, getNodeType(node))
+ if castNode(node) or node instanceof ArgNode or node instanceof ReturnNode
+ then compatibleTypes(t, getNodeDataFlowType(node))
else any()
}
@@ -129,7 +129,7 @@ private module LambdaFlow {
boolean toJump, DataFlowCallOption lastCall
) {
lambdaCall(lambdaCall, kind, node) and
- t = getNodeType(node) and
+ t = getNodeDataFlowType(node) and
toReturn = false and
toJump = false and
lastCall = TDataFlowCallNone()
@@ -146,7 +146,7 @@ private module LambdaFlow {
getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid)
|
preservesValue = false and
- t = getNodeType(node)
+ t = getNodeDataFlowType(node)
or
preservesValue = true and
t = t0
@@ -160,7 +160,7 @@ private module LambdaFlow {
toJump = true and
lastCall = TDataFlowCallNone()
|
- jumpStep(node, mid) and
+ jumpStepCached(node, mid) and
t = t0
or
exists(boolean preservesValue |
@@ -168,7 +168,7 @@ private module LambdaFlow {
getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid)
|
preservesValue = false and
- t = getNodeType(node)
+ t = getNodeDataFlowType(node)
or
preservesValue = true and
t = t0
@@ -176,7 +176,7 @@ private module LambdaFlow {
)
or
// flow into a callable
- exists(ParameterNode p, DataFlowCallOption lastCall0, DataFlowCall call |
+ exists(ParamNode p, DataFlowCallOption lastCall0, DataFlowCall call |
revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and
(
if lastCall0 = TDataFlowCallNone() and toJump = false
@@ -227,7 +227,7 @@ private module LambdaFlow {
pragma[nomagic]
predicate revLambdaFlowIn(
- DataFlowCall lambdaCall, LambdaCallKind kind, ParameterNode p, DataFlowType t, boolean toJump,
+ DataFlowCall lambdaCall, LambdaCallKind kind, ParamNode p, DataFlowType t, boolean toJump,
DataFlowCallOption lastCall
) {
revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall)
@@ -242,6 +242,89 @@ private DataFlowCallable viableCallableExt(DataFlowCall call) {
cached
private module Cached {
+ /**
+ * If needed, call this predicate from `DataFlowImplSpecific.qll` in order to
+ * force a stage-dependency on the `DataFlowImplCommon.qll` stage and therby
+ * collapsing the two stages.
+ */
+ cached
+ predicate forceCachingInSameStage() { any() }
+
+ cached
+ predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = n.getEnclosingCallable() }
+
+ cached
+ predicate callEnclosingCallable(DataFlowCall call, DataFlowCallable c) {
+ c = call.getEnclosingCallable()
+ }
+
+ cached
+ predicate nodeDataFlowType(Node n, DataFlowType t) { t = getNodeType(n) }
+
+ cached
+ predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
+
+ cached
+ predicate clearsContentCached(Node n, Content c) { clearsContent(n, c) }
+
+ cached
+ predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
+
+ cached
+ predicate outNodeExt(Node n) {
+ n instanceof OutNode
+ or
+ n.(PostUpdateNode).getPreUpdateNode() instanceof ArgNode
+ }
+
+ cached
+ predicate hiddenNode(Node n) { nodeIsHidden(n) }
+
+ cached
+ OutNodeExt getAnOutNodeExt(DataFlowCall call, ReturnKindExt k) {
+ result = getAnOutNode(call, k.(ValueReturnKind).getKind())
+ or
+ exists(ArgNode arg |
+ result.(PostUpdateNode).getPreUpdateNode() = arg and
+ arg.argumentOf(call, k.(ParamUpdateReturnKind).getPosition())
+ )
+ }
+
+ cached
+ predicate returnNodeExt(Node n, ReturnKindExt k) {
+ k = TValueReturn(n.(ReturnNode).getKind())
+ or
+ exists(ParamNode p, int pos |
+ parameterValueFlowsToPreUpdate(p, n) and
+ p.isParameterOf(_, pos) and
+ k = TParamUpdate(pos)
+ )
+ }
+
+ cached
+ predicate castNode(Node n) { n instanceof CastNode }
+
+ cached
+ predicate castingNode(Node n) {
+ castNode(n) or
+ n instanceof ParamNode or
+ n instanceof OutNodeExt or
+ // For reads, `x.f`, we want to check that the tracked type after the read (which
+ // is obtained by popping the head of the access path stack) is compatible with
+ // the type of `x.f`.
+ read(_, _, n)
+ }
+
+ cached
+ predicate parameterNode(Node n, DataFlowCallable c, int i) {
+ n.(ParameterNode).isParameterOf(c, i)
+ }
+
+ cached
+ predicate argumentNode(Node n, DataFlowCall call, int pos) {
+ n.(ArgumentNode).argumentOf(call, pos)
+ }
+
/**
* Gets a viable target for the lambda call `call`.
*
@@ -261,7 +344,7 @@ private module Cached {
* The instance parameter is considered to have index `-1`.
*/
pragma[nomagic]
- private predicate viableParam(DataFlowCall call, int i, ParameterNode p) {
+ private predicate viableParam(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallableExt(call), i)
}
@@ -270,11 +353,11 @@ private module Cached {
* dispatch into account.
*/
cached
- predicate viableParamArg(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
+ predicate viableParamArg(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i |
viableParam(call, i, p) and
arg.argumentOf(call, i) and
- compatibleTypes(getNodeType(arg), getNodeType(p))
+ compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
)
}
@@ -312,7 +395,7 @@ private module Cached {
* `read` indicates whether it is contents of `p` that can flow to `node`.
*/
pragma[nomagic]
- private predicate parameterValueFlowCand(ParameterNode p, Node node, boolean read) {
+ private predicate parameterValueFlowCand(ParamNode p, Node node, boolean read) {
p = node and
read = false
or
@@ -325,30 +408,30 @@ private module Cached {
// read
exists(Node mid |
parameterValueFlowCand(p, mid, false) and
- readStep(mid, _, node) and
+ read(mid, _, node) and
read = true
)
or
// flow through: no prior read
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
parameterValueFlowArgCand(p, arg, false) and
argumentValueFlowsThroughCand(arg, node, read)
)
or
// flow through: no read inside method
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
parameterValueFlowArgCand(p, arg, read) and
argumentValueFlowsThroughCand(arg, node, false)
)
}
pragma[nomagic]
- private predicate parameterValueFlowArgCand(ParameterNode p, ArgumentNode arg, boolean read) {
+ private predicate parameterValueFlowArgCand(ParamNode p, ArgNode arg, boolean read) {
parameterValueFlowCand(p, arg, read)
}
pragma[nomagic]
- predicate parameterValueFlowsToPreUpdateCand(ParameterNode p, PostUpdateNode n) {
+ predicate parameterValueFlowsToPreUpdateCand(ParamNode p, PostUpdateNode n) {
parameterValueFlowCand(p, n.getPreUpdateNode(), false)
}
@@ -360,7 +443,7 @@ private module Cached {
* `read` indicates whether it is contents of `p` that can flow to the return
* node.
*/
- predicate parameterValueFlowReturnCand(ParameterNode p, ReturnKind kind, boolean read) {
+ predicate parameterValueFlowReturnCand(ParamNode p, ReturnKind kind, boolean read) {
exists(ReturnNode ret |
parameterValueFlowCand(p, ret, read) and
kind = ret.getKind()
@@ -369,9 +452,9 @@ private module Cached {
pragma[nomagic]
private predicate argumentValueFlowsThroughCand0(
- DataFlowCall call, ArgumentNode arg, ReturnKind kind, boolean read
+ DataFlowCall call, ArgNode arg, ReturnKind kind, boolean read
) {
- exists(ParameterNode param | viableParamArg(call, param, arg) |
+ exists(ParamNode param | viableParamArg(call, param, arg) |
parameterValueFlowReturnCand(param, kind, read)
)
}
@@ -382,14 +465,14 @@ private module Cached {
*
* `read` indicates whether it is contents of `arg` that can flow to `out`.
*/
- predicate argumentValueFlowsThroughCand(ArgumentNode arg, Node out, boolean read) {
+ predicate argumentValueFlowsThroughCand(ArgNode arg, Node out, boolean read) {
exists(DataFlowCall call, ReturnKind kind |
argumentValueFlowsThroughCand0(call, arg, kind, read) and
out = getAnOutNode(call, kind)
)
}
- predicate cand(ParameterNode p, Node n) {
+ predicate cand(ParamNode p, Node n) {
parameterValueFlowCand(p, n, _) and
(
parameterValueFlowReturnCand(p, _, _)
@@ -416,21 +499,21 @@ private module Cached {
* If a read step was taken, then `read` captures the `Content`, the
* container type, and the content type.
*/
- predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) {
+ predicate parameterValueFlow(ParamNode p, Node node, ReadStepTypesOption read) {
parameterValueFlow0(p, node, read) and
if node instanceof CastingNode
then
// normal flow through
read = TReadStepTypesNone() and
- compatibleTypes(getNodeType(p), getNodeType(node))
+ compatibleTypes(getNodeDataFlowType(p), getNodeDataFlowType(node))
or
// getter
- compatibleTypes(read.getContentType(), getNodeType(node))
+ compatibleTypes(read.getContentType(), getNodeDataFlowType(node))
else any()
}
pragma[nomagic]
- private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) {
+ private predicate parameterValueFlow0(ParamNode p, Node node, ReadStepTypesOption read) {
p = node and
Cand::cand(p, _) and
read = TReadStepTypesNone()
@@ -447,7 +530,7 @@ private module Cached {
readStepWithTypes(mid, read.getContainerType(), read.getContent(), node,
read.getContentType()) and
Cand::parameterValueFlowReturnCand(p, _, true) and
- compatibleTypes(getNodeType(p), read.getContainerType())
+ compatibleTypes(getNodeDataFlowType(p), read.getContainerType())
)
or
parameterValueFlow0_0(TReadStepTypesNone(), p, node, read)
@@ -455,34 +538,32 @@ private module Cached {
pragma[nomagic]
private predicate parameterValueFlow0_0(
- ReadStepTypesOption mustBeNone, ParameterNode p, Node node, ReadStepTypesOption read
+ ReadStepTypesOption mustBeNone, ParamNode p, Node node, ReadStepTypesOption read
) {
// flow through: no prior read
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
parameterValueFlowArg(p, arg, mustBeNone) and
argumentValueFlowsThrough(arg, read, node)
)
or
// flow through: no read inside method
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
parameterValueFlowArg(p, arg, read) and
argumentValueFlowsThrough(arg, mustBeNone, node)
)
}
pragma[nomagic]
- private predicate parameterValueFlowArg(
- ParameterNode p, ArgumentNode arg, ReadStepTypesOption read
- ) {
+ private predicate parameterValueFlowArg(ParamNode p, ArgNode arg, ReadStepTypesOption read) {
parameterValueFlow(p, arg, read) and
Cand::argumentValueFlowsThroughCand(arg, _, _)
}
pragma[nomagic]
private predicate argumentValueFlowsThrough0(
- DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read
+ DataFlowCall call, ArgNode arg, ReturnKind kind, ReadStepTypesOption read
) {
- exists(ParameterNode param | viableParamArg(call, param, arg) |
+ exists(ParamNode param | viableParamArg(call, param, arg) |
parameterValueFlowReturn(param, kind, read)
)
}
@@ -496,18 +577,18 @@ private module Cached {
* container type, and the content type.
*/
pragma[nomagic]
- predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) {
+ predicate argumentValueFlowsThrough(ArgNode arg, ReadStepTypesOption read, Node out) {
exists(DataFlowCall call, ReturnKind kind |
argumentValueFlowsThrough0(call, arg, kind, read) and
out = getAnOutNode(call, kind)
|
// normal flow through
read = TReadStepTypesNone() and
- compatibleTypes(getNodeType(arg), getNodeType(out))
+ compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(out))
or
// getter
- compatibleTypes(getNodeType(arg), read.getContainerType()) and
- compatibleTypes(read.getContentType(), getNodeType(out))
+ compatibleTypes(getNodeDataFlowType(arg), read.getContainerType()) and
+ compatibleTypes(read.getContentType(), getNodeDataFlowType(out))
)
}
@@ -516,7 +597,7 @@ private module Cached {
* value-preserving steps and a single read step, not taking call
* contexts into account, thus representing a getter-step.
*/
- predicate getterStep(ArgumentNode arg, Content c, Node out) {
+ predicate getterStep(ArgNode arg, Content c, Node out) {
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
}
@@ -529,7 +610,7 @@ private module Cached {
* container type, and the content type.
*/
private predicate parameterValueFlowReturn(
- ParameterNode p, ReturnKind kind, ReadStepTypesOption read
+ ParamNode p, ReturnKind kind, ReadStepTypesOption read
) {
exists(ReturnNode ret |
parameterValueFlow(p, ret, read) and
@@ -553,7 +634,7 @@ private module Cached {
private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) {
mayBenefitFromCallContext(call, callable)
or
- callable = call.getEnclosingCallable() and
+ callEnclosingCallable(call, callable) and
exists(viableCallableLambda(call, TDataFlowCallSome(_)))
}
@@ -611,7 +692,7 @@ private module Cached {
mayBenefitFromCallContextExt(call, _) and
c = viableCallableExt(call) and
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and
- tgts = strictcount(DataFlowCall ctx | viableCallableExt(ctx) = call.getEnclosingCallable()) and
+ tgts = strictcount(DataFlowCall ctx | callEnclosingCallable(call, viableCallableExt(ctx))) and
ctxtgts < tgts
)
}
@@ -635,8 +716,7 @@ private module Cached {
* Holds if `p` can flow to the pre-update node associated with post-update
* node `n`, in the same callable, using only value-preserving steps.
*/
- cached
- predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) {
+ private predicate parameterValueFlowsToPreUpdate(ParamNode p, PostUpdateNode n) {
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
}
@@ -644,9 +724,9 @@ private module Cached {
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
) {
storeStep(node1, c, node2) and
- readStep(_, c, _) and
- contentType = getNodeType(node1) and
- containerType = getNodeType(node2)
+ read(_, c, _) and
+ contentType = getNodeDataFlowType(node1) and
+ containerType = getNodeDataFlowType(node2)
or
exists(Node n1, Node n2 |
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
@@ -654,12 +734,15 @@ private module Cached {
|
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
or
- readStep(n2, c, n1) and
- contentType = getNodeType(n1) and
- containerType = getNodeType(n2)
+ read(n2, c, n1) and
+ contentType = getNodeDataFlowType(n1) and
+ containerType = getNodeDataFlowType(n2)
)
}
+ cached
+ predicate read(Node node1, Content c, Node node2) { readStep(node1, c, node2) }
+
/**
* Holds if data can flow from `node1` to `node2` via a direct assignment to
* `f`.
@@ -678,8 +761,9 @@ private module Cached {
* are aliases. A typical example is a function returning `this`, implementing a fluent
* interface.
*/
- cached
- predicate reverseStepThroughInputOutputAlias(PostUpdateNode fromNode, PostUpdateNode toNode) {
+ private predicate reverseStepThroughInputOutputAlias(
+ PostUpdateNode fromNode, PostUpdateNode toNode
+ ) {
exists(Node fromPre, Node toPre |
fromPre = fromNode.getPreUpdateNode() and
toPre = toNode.getPreUpdateNode()
@@ -688,14 +772,20 @@ private module Cached {
// Does the language-specific simpleLocalFlowStep already model flow
// from function input to output?
fromPre = getAnOutNode(c, _) and
- toPre.(ArgumentNode).argumentOf(c, _) and
- simpleLocalFlowStep(toPre.(ArgumentNode), fromPre)
+ toPre.(ArgNode).argumentOf(c, _) and
+ simpleLocalFlowStep(toPre.(ArgNode), fromPre)
)
or
argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre)
)
}
+ cached
+ predicate simpleLocalFlowStepExt(Node node1, Node node2) {
+ simpleLocalFlowStep(node1, node2) or
+ reverseStepThroughInputOutputAlias(node1, node2)
+ }
+
/**
* Holds if the call context `call` either improves virtual dispatch in
* `callable` or if it allows us to prune unreachable nodes in `callable`.
@@ -704,7 +794,7 @@ private module Cached {
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
reducedViableImplInCallContext(_, callable, call)
or
- exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCall(n, call))
+ exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call))
}
cached
@@ -726,12 +816,12 @@ private module Cached {
cached
newtype TLocalFlowCallContext =
TAnyLocalCall() or
- TSpecificLocalCall(DataFlowCall call) { isUnreachableInCall(_, call) }
+ TSpecificLocalCall(DataFlowCall call) { isUnreachableInCallCached(_, call) }
cached
newtype TReturnKindExt =
TValueReturn(ReturnKind kind) or
- TParamUpdate(int pos) { exists(ParameterNode p | p.isParameterOf(_, pos)) }
+ TParamUpdate(int pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
cached
newtype TBooleanOption =
@@ -761,23 +851,15 @@ private module Cached {
* A `Node` at which a cast can occur such that the type should be checked.
*/
class CastingNode extends Node {
- CastingNode() {
- this instanceof ParameterNode or
- this instanceof CastNode or
- this instanceof OutNodeExt or
- // For reads, `x.f`, we want to check that the tracked type after the read (which
- // is obtained by popping the head of the access path stack) is compatible with
- // the type of `x.f`.
- readStep(_, _, this)
- }
+ CastingNode() { castingNode(this) }
}
private predicate readStepWithTypes(
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
) {
- readStep(n1, c, n2) and
- container = getNodeType(n1) and
- content = getNodeType(n2)
+ read(n1, c, n2) and
+ container = getNodeDataFlowType(n1) and
+ content = getNodeDataFlowType(n2)
}
private newtype TReadStepTypesOption =
@@ -854,7 +936,7 @@ class CallContextSomeCall extends CallContextCall, TSomeCall {
override string toString() { result = "CcSomeCall" }
override predicate relevantFor(DataFlowCallable callable) {
- exists(ParameterNode p | getNodeEnclosingCallable(p) = callable)
+ exists(ParamNode p | getNodeEnclosingCallable(p) = callable)
}
override predicate matchesCall(DataFlowCall call) { any() }
@@ -866,7 +948,7 @@ class CallContextReturn extends CallContextNoCall, TReturn {
}
override predicate relevantFor(DataFlowCallable callable) {
- exists(DataFlowCall call | this = TReturn(_, call) and call.getEnclosingCallable() = callable)
+ exists(DataFlowCall call | this = TReturn(_, call) and callEnclosingCallable(call, callable))
}
}
@@ -899,7 +981,7 @@ class LocalCallContextSpecificCall extends LocalCallContext, TSpecificLocalCall
}
private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) {
- exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCall(n, call))
+ exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCallCached(n, call))
}
/**
@@ -913,26 +995,37 @@ LocalCallContext getLocalCallContext(CallContext ctx, DataFlowCallable callable)
else result instanceof LocalCallContextAny
}
+/**
+ * The value of a parameter at function entry, viewed as a node in a data
+ * flow graph.
+ */
+class ParamNode extends Node {
+ ParamNode() { parameterNode(this, _, _) }
+
+ /**
+ * Holds if this node is the parameter of callable `c` at the specified
+ * (zero-based) position.
+ */
+ predicate isParameterOf(DataFlowCallable c, int i) { parameterNode(this, c, i) }
+}
+
+/** A data-flow node that represents a call argument. */
+class ArgNode extends Node {
+ ArgNode() { argumentNode(this, _, _) }
+
+ /** Holds if this argument occurs at the given position in the given call. */
+ final predicate argumentOf(DataFlowCall call, int pos) { argumentNode(this, call, pos) }
+}
+
/**
* A node from which flow can return to the caller. This is either a regular
* `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter.
*/
class ReturnNodeExt extends Node {
- ReturnNodeExt() {
- this instanceof ReturnNode or
- parameterValueFlowsToPreUpdate(_, this)
- }
+ ReturnNodeExt() { returnNodeExt(this, _) }
/** Gets the kind of this returned value. */
- ReturnKindExt getKind() {
- result = TValueReturn(this.(ReturnNode).getKind())
- or
- exists(ParameterNode p, int pos |
- parameterValueFlowsToPreUpdate(p, this) and
- p.isParameterOf(_, pos) and
- result = TParamUpdate(pos)
- )
- }
+ ReturnKindExt getKind() { returnNodeExt(this, result) }
}
/**
@@ -940,11 +1033,7 @@ class ReturnNodeExt extends Node {
* or a post-update node associated with a call argument.
*/
class OutNodeExt extends Node {
- OutNodeExt() {
- this instanceof OutNode
- or
- this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode
- }
+ OutNodeExt() { outNodeExt(this) }
}
/**
@@ -957,7 +1046,7 @@ abstract class ReturnKindExt extends TReturnKindExt {
abstract string toString();
/** Gets a node corresponding to data flow out of `call`. */
- abstract OutNodeExt getAnOutNode(DataFlowCall call);
+ final OutNodeExt getAnOutNode(DataFlowCall call) { result = getAnOutNodeExt(call, this) }
}
class ValueReturnKind extends ReturnKindExt, TValueReturn {
@@ -968,10 +1057,6 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn {
ReturnKind getKind() { result = kind }
override string toString() { result = kind.toString() }
-
- override OutNodeExt getAnOutNode(DataFlowCall call) {
- result = getAnOutNode(call, this.getKind())
- }
}
class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
@@ -982,13 +1067,6 @@ class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
int getPosition() { result = pos }
override string toString() { result = "param update " + pos }
-
- override OutNodeExt getAnOutNode(DataFlowCall call) {
- exists(ArgumentNode arg |
- result.(PostUpdateNode).getPreUpdateNode() = arg and
- arg.argumentOf(call, this.getPosition())
- )
- }
}
/** A callable tagged with a relevant return kind. */
@@ -1015,10 +1093,13 @@ class ReturnPosition extends TReturnPosition0 {
*/
pragma[inline]
DataFlowCallable getNodeEnclosingCallable(Node n) {
- exists(Node n0 |
- pragma[only_bind_into](n0) = n and
- pragma[only_bind_into](result) = n0.getEnclosingCallable()
- )
+ nodeEnclosingCallable(pragma[only_bind_out](n), pragma[only_bind_into](result))
+}
+
+/** Gets the type of `n` used for type pruning. */
+pragma[inline]
+DataFlowType getNodeDataFlowType(Node n) {
+ nodeDataFlowType(pragma[only_bind_out](n), pragma[only_bind_into](result))
}
pragma[noinline]
@@ -1042,7 +1123,7 @@ predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall
cc instanceof CallContextAny and callable = viableCallableExt(call)
or
exists(DataFlowCallable c0, DataFlowCall call0 |
- call0.getEnclosingCallable() = callable and
+ callEnclosingCallable(call0, callable) and
cc = TReturn(c0, call0) and
c0 = prunedViableImplInCallContextReverse(call0, call)
)
@@ -1063,8 +1144,6 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
result = viableCallableExt(call) and cc instanceof CallContextReturn
}
-predicate read = readStep/3;
-
/** An optional Boolean value. */
class BooleanOption extends TBooleanOption {
string toString() {
@@ -1116,7 +1195,7 @@ abstract class AccessPathFront extends TAccessPathFront {
TypedContent getHead() { this = TFrontHead(result) }
- predicate isClearedAt(Node n) { clearsContent(n, getHead().getContent()) }
+ predicate isClearedAt(Node n) { clearsContentCached(n, getHead().getContent()) }
}
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowNodes.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowNodes.qll
index 552849c2c34..c47efa287ad 100644
--- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowNodes.qll
+++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowNodes.qll
@@ -4,71 +4,48 @@ private import semmle.code.java.dataflow.FlowSummary
private import semmle.code.java.dataflow.TypeFlow
private import DataFlowPrivate
private import FlowSummaryImpl as FlowSummaryImpl
+private import DataFlowImplCommon as DataFlowImplCommon
cached
-private module Cached {
- cached
- newtype TNode =
- TExprNode(Expr e) {
- not e.getType() instanceof VoidType and
- not e.getParent*() instanceof Annotation
- } or
- TExplicitParameterNode(Parameter p) {
- exists(p.getCallable().getBody()) or p.getCallable() instanceof SummarizedCallable
- } or
- TImplicitVarargsArray(Call c) {
- c.getCallee().isVarargs() and
- not exists(Argument arg | arg.getCall() = c and arg.isExplicitVarargsArray())
- } or
- TInstanceParameterNode(Callable c) {
- (exists(c.getBody()) or c instanceof SummarizedCallable) and
- not c.isStatic()
- } or
- TImplicitInstanceAccess(InstanceAccessExt ia) { not ia.isExplicit(_) } or
- TMallocNode(ClassInstanceExpr cie) or
- TExplicitExprPostUpdate(Expr e) {
- explicitInstanceArgument(_, e)
- or
- e instanceof Argument and not e.getType() instanceof ImmutableType
- or
- exists(FieldAccess fa | fa.getField() instanceof InstanceField and e = fa.getQualifier())
- or
- exists(ArrayAccess aa | e = aa.getArray())
- } or
- TImplicitExprPostUpdate(InstanceAccessExt ia) {
- implicitInstanceArgument(_, ia)
- or
- exists(FieldAccess fa |
- fa.getField() instanceof InstanceField and ia.isImplicitFieldQualifier(fa)
- )
- } or
- TSummaryInternalNode(SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state) {
- FlowSummaryImpl::Private::summaryNodeRange(c, state)
- }
-
- cached
- predicate summaryOutNodeCached(DataFlowCall c, Node out) {
- FlowSummaryImpl::Private::summaryOutNode(c, out, _)
+newtype TNode =
+ TExprNode(Expr e) {
+ DataFlowImplCommon::forceCachingInSameStage() and
+ not e.getType() instanceof VoidType and
+ not e.getParent*() instanceof Annotation
+ } or
+ TExplicitParameterNode(Parameter p) {
+ exists(p.getCallable().getBody()) or p.getCallable() instanceof SummarizedCallable
+ } or
+ TImplicitVarargsArray(Call c) {
+ c.getCallee().isVarargs() and
+ not exists(Argument arg | arg.getCall() = c and arg.isExplicitVarargsArray())
+ } or
+ TInstanceParameterNode(Callable c) {
+ (exists(c.getBody()) or c instanceof SummarizedCallable) and
+ not c.isStatic()
+ } or
+ TImplicitInstanceAccess(InstanceAccessExt ia) { not ia.isExplicit(_) } or
+ TMallocNode(ClassInstanceExpr cie) or
+ TExplicitExprPostUpdate(Expr e) {
+ explicitInstanceArgument(_, e)
+ or
+ e instanceof Argument and not e.getType() instanceof ImmutableType
+ or
+ exists(FieldAccess fa | fa.getField() instanceof InstanceField and e = fa.getQualifier())
+ or
+ exists(ArrayAccess aa | e = aa.getArray())
+ } or
+ TImplicitExprPostUpdate(InstanceAccessExt ia) {
+ implicitInstanceArgument(_, ia)
+ or
+ exists(FieldAccess fa |
+ fa.getField() instanceof InstanceField and ia.isImplicitFieldQualifier(fa)
+ )
+ } or
+ TSummaryInternalNode(SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state) {
+ FlowSummaryImpl::Private::summaryNodeRange(c, state)
}
- cached
- predicate summaryArgumentNodeCached(DataFlowCall c, Node arg, int i) {
- FlowSummaryImpl::Private::summaryArgumentNode(c, arg, i)
- }
-
- cached
- predicate summaryPostUpdateNodeCached(Node post, ParameterNode pre) {
- FlowSummaryImpl::Private::summaryPostUpdateNode(post, pre)
- }
-
- cached
- predicate summaryReturnNodeCached(Node ret) {
- FlowSummaryImpl::Private::summaryReturnNode(ret, _)
- }
-}
-
-private import Cached
-
private predicate explicitInstanceArgument(Call call, Expr instarg) {
call instanceof MethodAccess and
instarg = call.getQualifier() and
@@ -404,13 +381,15 @@ module Private {
override string toString() { result = "[summary] " + state + " in " + c }
/** Holds if this summary node is the `i`th argument of `call`. */
- predicate isArgumentOf(DataFlowCall call, int i) { summaryArgumentNodeCached(call, this, i) }
+ predicate isArgumentOf(DataFlowCall call, int i) {
+ FlowSummaryImpl::Private::summaryArgumentNode(call, this, i)
+ }
/** Holds if this summary node is a return node. */
- predicate isReturn() { summaryReturnNodeCached(this) }
+ predicate isReturn() { FlowSummaryImpl::Private::summaryReturnNode(this, _) }
/** Holds if this summary node is an out node for `call`. */
- predicate isOut(DataFlowCall call) { summaryOutNodeCached(call, this) }
+ predicate isOut(DataFlowCall call) { FlowSummaryImpl::Private::summaryOutNode(call, this, _) }
}
SummaryNode getSummaryNode(SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state) {
@@ -439,7 +418,7 @@ private class MallocNode extends Node, TMallocNode {
private class SummaryPostUpdateNode extends SummaryNode, PostUpdateNode {
private Node pre;
- SummaryPostUpdateNode() { summaryPostUpdateNodeCached(this, pre) }
+ SummaryPostUpdateNode() { FlowSummaryImpl::Private::summaryPostUpdateNode(this, pre) }
override Node getPreUpdateNode() { result = pre }
}
diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowPrivate.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowPrivate.qll
index 2e22b7e1963..e3ab07fce1f 100644
--- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowPrivate.qll
+++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowPrivate.qll
@@ -284,7 +284,6 @@ private class ConstantBooleanArgumentNode extends ArgumentNode, ExprNode {
/**
* Holds if the node `n` is unreachable when the call context is `call`.
*/
-cached
predicate isUnreachableInCall(Node n, DataFlowCall call) {
exists(
ExplicitParameterNode paramNode, ConstantBooleanArgumentNode arg, SsaImplicitInit param,
diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowUtil.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowUtil.qll
index 2ad09574015..e25ab24cfbb 100644
--- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowUtil.qll
+++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowUtil.qll
@@ -11,6 +11,7 @@ private import semmle.code.java.dataflow.FlowSteps
private import semmle.code.java.dataflow.FlowSummary
import semmle.code.java.dataflow.InstanceAccess
private import FlowSummaryImpl as FlowSummaryImpl
+private import TaintTrackingUtil as TaintTrackingUtil
import DataFlowNodes::Public
/** Holds if `n` is an access to an unqualified `this` at `cfgnode`. */
@@ -112,6 +113,7 @@ predicate localFlowStep(Node node1, Node node2) {
*/
cached
predicate simpleLocalFlowStep(Node node1, Node node2) {
+ TaintTrackingUtil::forceCachingInSameStage() and
// Variable flow steps through adjacent def-use and use-use pairs.
exists(SsaExplicitUpdate upd |
upd.getDefiningExpr().(VariableAssign).getSource() = node1.asExpr() or
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 f9278ab815e..8c514e357d2 100644
--- a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll
+++ b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll
@@ -29,55 +29,69 @@ predicate localExprTaint(Expr src, Expr sink) {
localTaint(DataFlow::exprNode(src), DataFlow::exprNode(sink))
}
-/**
- * Holds if taint can flow in one local step from `src` to `sink`.
- */
-predicate localTaintStep(DataFlow::Node src, DataFlow::Node sink) {
- DataFlow::localFlowStep(src, sink) or
- localAdditionalTaintStep(src, sink) or
- // Simple flow through library code is included in the exposed local
- // step relation, even though flow is technically inter-procedural
- FlowSummaryImpl::Private::Steps::summaryThroughStep(src, sink, false)
+cached
+private module Cached {
+ private import DataFlowImplCommon as DataFlowImplCommon
+
+ cached
+ predicate forceCachingInSameStage() { DataFlowImplCommon::forceCachingInSameStage() }
+
+ /**
+ * Holds if taint can flow in one local step from `src` to `sink`.
+ */
+ cached
+ predicate localTaintStep(DataFlow::Node src, DataFlow::Node sink) {
+ DataFlow::localFlowStep(src, sink) or
+ localAdditionalTaintStep(src, sink) or
+ // Simple flow through library code is included in the exposed local
+ // step relation, even though flow is technically inter-procedural
+ FlowSummaryImpl::Private::Steps::summaryThroughStep(src, sink, false)
+ }
+
+ /**
+ * Holds if taint can flow in one local step from `src` to `sink` excluding
+ * local data flow steps. That is, `src` and `sink` are likely to represent
+ * different objects.
+ */
+ cached
+ predicate localAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
+ localAdditionalTaintExprStep(src.asExpr(), sink.asExpr())
+ or
+ localAdditionalTaintUpdateStep(src.asExpr(),
+ sink.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr())
+ or
+ exists(Argument arg |
+ src.asExpr() = arg and
+ arg.isVararg() and
+ sink.(DataFlow::ImplicitVarargsArray).getCall() = arg.getCall()
+ )
+ or
+ FlowSummaryImpl::Private::Steps::summaryLocalStep(src, sink, false)
+ }
+
+ /**
+ * Holds if the additional step from `src` to `sink` should be included in all
+ * global taint flow configurations.
+ */
+ cached
+ predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
+ localAdditionalTaintStep(src, sink) or
+ any(AdditionalTaintStep a).step(src, sink)
+ }
+
+ /**
+ * Holds if `node` should be a sanitizer in all global taint flow configurations
+ * but not in local taint.
+ */
+ cached
+ predicate defaultTaintSanitizer(DataFlow::Node node) {
+ // Ignore paths through test code.
+ node.getEnclosingCallable().getDeclaringType() instanceof NonSecurityTestClass or
+ node.asExpr() instanceof ValidatedVariableAccess
+ }
}
-/**
- * Holds if taint can flow in one local step from `src` to `sink` excluding
- * local data flow steps. That is, `src` and `sink` are likely to represent
- * different objects.
- */
-predicate localAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
- localAdditionalTaintExprStep(src.asExpr(), sink.asExpr())
- or
- localAdditionalTaintUpdateStep(src.asExpr(),
- sink.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr())
- or
- exists(Argument arg |
- src.asExpr() = arg and
- arg.isVararg() and
- sink.(DataFlow::ImplicitVarargsArray).getCall() = arg.getCall()
- )
- or
- FlowSummaryImpl::Private::Steps::summaryLocalStep(src, sink, false)
-}
-
-/**
- * Holds if the additional step from `src` to `sink` should be included in all
- * global taint flow configurations.
- */
-predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
- localAdditionalTaintStep(src, sink) or
- any(AdditionalTaintStep a).step(src, sink)
-}
-
-/**
- * Holds if `node` should be a sanitizer in all global taint flow configurations
- * but not in local taint.
- */
-predicate defaultTaintSanitizer(DataFlow::Node node) {
- // Ignore paths through test code.
- node.getEnclosingCallable().getDeclaringType() instanceof NonSecurityTestClass or
- node.asExpr() instanceof ValidatedVariableAccess
-}
+import Cached
/**
* Holds if taint can flow in one local step from `src` to `sink` excluding
diff --git a/java/ql/src/semmle/code/java/frameworks/Kryo.qll b/java/ql/src/semmle/code/java/frameworks/Kryo.qll
index 049be97ea9c..317148d56b5 100644
--- a/java/ql/src/semmle/code/java/frameworks/Kryo.qll
+++ b/java/ql/src/semmle/code/java/frameworks/Kryo.qll
@@ -3,19 +3,60 @@
*/
import java
+private import semmle.code.java.dataflow.DataFlow
+private import semmle.code.java.dataflow.FlowSteps
/**
* The type `com.esotericsoftware.kryo.Kryo`.
*/
class Kryo extends RefType {
- Kryo() { this.hasQualifiedName("com.esotericsoftware.kryo", "Kryo") }
+ Kryo() {
+ hasQualifiedName("com.esotericsoftware.kryo", "Kryo") or
+ hasQualifiedName("com.esotericsoftware.kryo5", "Kryo")
+ }
}
/**
* A Kryo input stream.
*/
class KryoInput extends RefType {
- KryoInput() { this.hasQualifiedName("com.esotericsoftware.kryo.io", "Input") }
+ KryoInput() {
+ hasQualifiedName("com.esotericsoftware.kryo.io", "Input") or
+ hasQualifiedName("com.esotericsoftware.kryo5.io", "Input")
+ }
+}
+
+/**
+ * A Kryo pool.
+ */
+class KryoPool extends RefType {
+ KryoPool() {
+ hasQualifiedName("com.esotericsoftware.kryo.pool", "KryoPool") or
+ hasQualifiedName("com.esotericsoftware.kryo5.pool", "KryoPool")
+ }
+}
+
+/**
+ * A Kryo pool builder.
+ */
+class KryoPoolBuilder extends RefType {
+ KryoPoolBuilder() {
+ hasQualifiedName("com.esotericsoftware.kryo.pool", "KryoPool$Builder") or
+ hasQualifiedName("com.esotericsoftware.kryo5.pool", "KryoPool$Builder")
+ }
+}
+
+/**
+ * A Kryo pool builder method used in a fluent API call chain.
+ */
+class KryoPoolBuilderMethod extends Method {
+ KryoPoolBuilderMethod() {
+ getDeclaringType() instanceof KryoPoolBuilder and
+ (
+ getReturnType() instanceof KryoPoolBuilder or
+ getReturnType() instanceof KryoPool
+ )
+ }
}
/**
@@ -45,3 +86,13 @@ class KryoEnableWhiteListing extends MethodAccess {
)
}
}
+
+/**
+ * A KryoPool method that uses a Kryo instance.
+ */
+class KryoPoolRunMethod extends Method {
+ KryoPoolRunMethod() {
+ getDeclaringType() instanceof KryoPool and
+ hasName("run")
+ }
+}
diff --git a/java/ql/src/semmle/code/java/frameworks/jackson/JacksonSerializability.qll b/java/ql/src/semmle/code/java/frameworks/jackson/JacksonSerializability.qll
index 3356e31d965..6cda84512a0 100644
--- a/java/ql/src/semmle/code/java/frameworks/jackson/JacksonSerializability.qll
+++ b/java/ql/src/semmle/code/java/frameworks/jackson/JacksonSerializability.qll
@@ -9,6 +9,7 @@ import semmle.code.java.Reflection
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.DataFlow5
import semmle.code.java.dataflow.FlowSteps
+private import semmle.code.java.dataflow.ExternalFlow
/**
* A `@com.fasterxml.jackson.annotation.JsonIgnore` annoation.
@@ -28,7 +29,7 @@ abstract class JacksonSerializableType extends Type { }
* A method used for serializing objects using Jackson. The final parameter is the object to be
* serialized.
*/
-library class JacksonWriteValueMethod extends Method, TaintPreservingCallable {
+private class JacksonWriteValueMethod extends Method, TaintPreservingCallable {
JacksonWriteValueMethod() {
(
getDeclaringType().hasQualifiedName("com.fasterxml.jackson.databind", "ObjectWriter") or
@@ -50,8 +51,20 @@ library class JacksonWriteValueMethod extends Method, TaintPreservingCallable {
}
}
+private class JacksonReadValueMethod extends Method, TaintPreservingCallable {
+ JacksonReadValueMethod() {
+ (
+ getDeclaringType().hasQualifiedName("com.fasterxml.jackson.databind", "ObjectReader") or
+ getDeclaringType().hasQualifiedName("com.fasterxml.jackson.databind", "ObjectMapper")
+ ) and
+ hasName(["readValue", "readValues"])
+ }
+
+ override predicate returnsTaintFrom(int arg) { arg = 0 }
+}
+
/** A type whose values are explicitly serialized in a call to a Jackson method. */
-library class ExplicitlyWrittenJacksonSerializableType extends JacksonSerializableType {
+private class ExplicitlyWrittenJacksonSerializableType extends JacksonSerializableType {
ExplicitlyWrittenJacksonSerializableType() {
exists(MethodAccess ma |
// A call to a Jackson write method...
@@ -63,7 +76,7 @@ library class ExplicitlyWrittenJacksonSerializableType extends JacksonSerializab
}
/** A type used in a `JacksonSerializableField` declaration. */
-library class FieldReferencedJacksonSerializableType extends JacksonSerializableType {
+private class FieldReferencedJacksonSerializableType extends JacksonSerializableType {
FieldReferencedJacksonSerializableType() {
exists(JacksonSerializableField f | usesType(f.getType(), this))
}
@@ -96,17 +109,24 @@ private class TypeLiteralToJacksonDatabindFlowConfiguration extends DataFlow5::C
}
/** A type whose values are explicitly deserialized in a call to a Jackson method. */
-library class ExplicitlyReadJacksonDeserializableType extends JacksonDeserializableType {
+private class ExplicitlyReadJacksonDeserializableType extends JacksonDeserializableType {
ExplicitlyReadJacksonDeserializableType() {
exists(TypeLiteralToJacksonDatabindFlowConfiguration conf |
usesType(conf.getSourceWithFlowToJacksonDatabind().getTypeName().getType(), this)
)
+ or
+ exists(MethodAccess ma |
+ // A call to a Jackson read method...
+ ma.getMethod() instanceof JacksonReadValueMethod and
+ // ...where `this` is used in the final argument, indicating that this type will be deserialized.
+ usesType(ma.getArgument(ma.getNumArgument() - 1).getType(), this)
+ )
}
}
/** A type used in a `JacksonDeserializableField` declaration. */
-library class FieldReferencedJacksonDeSerializableType extends JacksonDeserializableType {
- FieldReferencedJacksonDeSerializableType() {
+private class FieldReferencedJacksonDeserializableType extends JacksonDeserializableType {
+ FieldReferencedJacksonDeserializableType() {
exists(JacksonDeserializableField f | usesType(f.getType(), this))
}
}
@@ -135,6 +155,21 @@ class JacksonDeserializableField extends DeserializableField {
}
}
+/** A call to a field that may be deserialized using the Jackson JSON framework. */
+private class JacksonDeserializableFieldAccess extends FieldAccess {
+ JacksonDeserializableFieldAccess() { getField() instanceof JacksonDeserializableField }
+}
+
+/**
+ * When an object is deserialized by the Jackson JSON framework using a tainted input source,
+ * the fields that the framework deserialized are themselves tainted input data.
+ */
+private class JacksonDeserializedTaintStep extends AdditionalTaintStep {
+ override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
+ DataFlow::getFieldQualifier(node2.asExpr().(JacksonDeserializableFieldAccess)) = node1
+ }
+}
+
/**
* A call to the `addMixInAnnotations` or `addMixIn` Jackson method.
*
@@ -239,3 +274,13 @@ class JacksonMixedInCallable extends Callable {
)
}
}
+
+private class JacksonModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "com.fasterxml.jackson.databind;ObjectMapper;true;valueToTree;;;Argument[0];ReturnValue;taint",
+ "com.fasterxml.jackson.databind;ObjectMapper;true;convertValue;;;Argument[0];ReturnValue;taint"
+ ]
+ }
+}
diff --git a/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll b/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll
index ab809f07d6d..a1561c0e6cd 100644
--- a/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll
+++ b/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll
@@ -48,6 +48,65 @@ class SafeKryo extends DataFlow2::Configuration {
ma.getMethod() instanceof KryoReadObjectMethod
)
}
+
+ override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
+ stepKryoPoolBuilderFactoryArgToConstructor(node1, node2) or
+ stepKryoPoolRunMethodAccessQualifierToFunctionalArgument(node1, node2) or
+ stepKryoPoolBuilderChainMethod(node1, node2) or
+ stepKryoPoolBorrowMethod(node1, node2)
+ }
+
+ /**
+ * Holds when a functional expression is used to create a `KryoPool.Builder`.
+ * Eg. `new KryoPool.Builder(() -> new Kryo())`
+ */
+ private predicate stepKryoPoolBuilderFactoryArgToConstructor(
+ DataFlow::Node node1, DataFlow::Node node2
+ ) {
+ exists(ConstructorCall cc, FunctionalExpr fe |
+ cc.getConstructedType() instanceof KryoPoolBuilder and
+ fe.asMethod().getBody().getAStmt().(ReturnStmt).getResult() = node1.asExpr() and
+ node2.asExpr() = cc and
+ cc.getArgument(0) = fe
+ )
+ }
+
+ /**
+ * Holds when a `KryoPool.run` is called to use a `Kryo` instance.
+ * Eg. `pool.run(kryo -> ...)`
+ */
+ private predicate stepKryoPoolRunMethodAccessQualifierToFunctionalArgument(
+ DataFlow::Node node1, DataFlow::Node node2
+ ) {
+ exists(MethodAccess ma |
+ ma.getMethod() instanceof KryoPoolRunMethod and
+ node1.asExpr() = ma.getQualifier() and
+ ma.getArgument(0).(FunctionalExpr).asMethod().getParameter(0) = node2.asParameter()
+ )
+ }
+
+ /**
+ * Holds when a `KryoPool.Builder` method is called fluently.
+ */
+ private predicate stepKryoPoolBuilderChainMethod(DataFlow::Node node1, DataFlow::Node node2) {
+ exists(MethodAccess ma |
+ ma.getMethod() instanceof KryoPoolBuilderMethod and
+ ma = node2.asExpr() and
+ ma.getQualifier() = node1.asExpr()
+ )
+ }
+
+ /**
+ * Holds when a `KryoPool.borrow` method is called.
+ */
+ private predicate stepKryoPoolBorrowMethod(DataFlow::Node node1, DataFlow::Node node2) {
+ exists(MethodAccess ma |
+ ma.getMethod() =
+ any(Method m | m.getDeclaringType() instanceof KryoPool and m.hasName("borrow")) and
+ node1.asExpr() = ma.getQualifier() and
+ node2.asExpr() = ma
+ )
+ }
}
predicate unsafeDeserialization(MethodAccess ma, Expr sink) {
diff --git a/java/ql/src/semmle/code/java/security/XmlParsers.qll b/java/ql/src/semmle/code/java/security/XmlParsers.qll
index 685c5754fc9..5e2eb1caf8a 100644
--- a/java/ql/src/semmle/code/java/security/XmlParsers.qll
+++ b/java/ql/src/semmle/code/java/security/XmlParsers.qll
@@ -36,7 +36,10 @@ abstract class ParserConfig extends MethodAccess {
*/
predicate disables(Expr e) {
this.getArgument(0) = e and
- this.getArgument(1).(BooleanLiteral).getBooleanValue() = false
+ (
+ this.getArgument(1).(BooleanLiteral).getBooleanValue() = false or
+ this.getArgument(1).(FieldAccess).getField().hasQualifiedName("java.lang", "Boolean", "FALSE")
+ )
}
/**
@@ -44,7 +47,10 @@ abstract class ParserConfig extends MethodAccess {
*/
predicate enables(Expr e) {
this.getArgument(0) = e and
- this.getArgument(1).(BooleanLiteral).getBooleanValue() = true
+ (
+ this.getArgument(1).(BooleanLiteral).getBooleanValue() = true or
+ this.getArgument(1).(FieldAccess).getField().hasQualifiedName("java.lang", "Boolean", "TRUE")
+ )
}
}
diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/JythonInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-094/JythonInjection.expected
new file mode 100644
index 00000000000..4f66cc83fbd
--- /dev/null
+++ b/java/ql/test/experimental/query-tests/security/CWE-094/JythonInjection.expected
@@ -0,0 +1,21 @@
+edges
+| JythonInjection.java:28:23:28:50 | getParameter(...) : String | JythonInjection.java:36:30:36:33 | code |
+| JythonInjection.java:53:23:53:50 | getParameter(...) : String | JythonInjection.java:58:44:58:47 | code |
+| JythonInjection.java:73:23:73:50 | getParameter(...) : String | JythonInjection.java:81:35:81:38 | code |
+| JythonInjection.java:97:23:97:50 | getParameter(...) : String | JythonInjection.java:106:61:106:75 | getBytes(...) |
+nodes
+| JythonInjection.java:28:23:28:50 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| JythonInjection.java:36:30:36:33 | code | semmle.label | code |
+| JythonInjection.java:53:23:53:50 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| JythonInjection.java:58:44:58:47 | code | semmle.label | code |
+| JythonInjection.java:73:23:73:50 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| JythonInjection.java:81:35:81:38 | code | semmle.label | code |
+| JythonInjection.java:97:23:97:50 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| JythonInjection.java:106:61:106:75 | getBytes(...) | semmle.label | getBytes(...) |
+| JythonInjection.java:131:40:131:63 | getInputStream(...) | semmle.label | getInputStream(...) |
+#select
+| JythonInjection.java:36:13:36:34 | exec(...) | JythonInjection.java:28:23:28:50 | getParameter(...) : String | JythonInjection.java:36:30:36:33 | code | Jython evaluate $@. | JythonInjection.java:28:23:28:50 | getParameter(...) | user input |
+| JythonInjection.java:58:27:58:48 | eval(...) | JythonInjection.java:53:23:53:50 | getParameter(...) : String | JythonInjection.java:58:44:58:47 | code | Jython evaluate $@. | JythonInjection.java:53:23:53:50 | getParameter(...) | user input |
+| JythonInjection.java:81:13:81:39 | runsource(...) | JythonInjection.java:73:23:73:50 | getParameter(...) : String | JythonInjection.java:81:35:81:38 | code | Jython evaluate $@. | JythonInjection.java:73:23:73:50 | getParameter(...) | user input |
+| JythonInjection.java:106:29:106:134 | makeCode(...) | JythonInjection.java:97:23:97:50 | getParameter(...) : String | JythonInjection.java:106:61:106:75 | getBytes(...) | Jython evaluate $@. | JythonInjection.java:97:23:97:50 | getParameter(...) | user input |
+| JythonInjection.java:131:29:131:109 | compile(...) | JythonInjection.java:131:40:131:63 | getInputStream(...) | JythonInjection.java:131:40:131:63 | getInputStream(...) | Jython evaluate $@. | JythonInjection.java:131:40:131:63 | getInputStream(...) | user input |
diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/JythonInjection.java b/java/ql/test/experimental/query-tests/security/CWE-094/JythonInjection.java
new file mode 100644
index 00000000000..f9b29fec6cc
--- /dev/null
+++ b/java/ql/test/experimental/query-tests/security/CWE-094/JythonInjection.java
@@ -0,0 +1,144 @@
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.python.core.BytecodeLoader;
+import org.python.core.Py;
+import org.python.core.PyCode;
+import org.python.core.PyException;
+import org.python.core.PyObject;
+import org.python.util.InteractiveInterpreter;
+import org.python.util.PythonInterpreter;
+
+public class JythonInjection extends HttpServlet {
+ private static final long serialVersionUID = 1L;
+
+ public JythonInjection() {
+ super();
+ }
+
+ // BAD: allow execution of arbitrary Python code
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ response.setContentType("text/plain");
+ String code = request.getParameter("code");
+ PythonInterpreter interpreter = null;
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+ try {
+ interpreter = new PythonInterpreter();
+ interpreter.setOut(out);
+ interpreter.setErr(out);
+ interpreter.exec(code);
+ out.flush();
+
+ response.getWriter().print(out.toString());
+ } catch(PyException ex) {
+ response.getWriter().println(ex.getMessage());
+ } finally {
+ if (interpreter != null) {
+ interpreter.close();
+ }
+ out.close();
+ }
+ }
+
+ // BAD: allow execution of arbitrary Python code
+ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ response.setContentType("text/plain");
+ String code = request.getParameter("code");
+ PythonInterpreter interpreter = null;
+
+ try {
+ interpreter = new PythonInterpreter();
+ PyObject py = interpreter.eval(code);
+
+ response.getWriter().print(py.toString());
+ } catch(PyException ex) {
+ response.getWriter().println(ex.getMessage());
+ } finally {
+ if (interpreter != null) {
+ interpreter.close();
+ }
+ }
+ }
+
+ // BAD: allow arbitrary Jython expression to run
+ protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ response.setContentType("text/plain");
+ String code = request.getParameter("code");
+ InteractiveInterpreter interpreter = null;
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+ try {
+ interpreter = new InteractiveInterpreter();
+ interpreter.setOut(out);
+ interpreter.setErr(out);
+ interpreter.runsource(code);
+ out.flush();
+
+ response.getWriter().print(out.toString());
+ } catch(PyException ex) {
+ response.getWriter().println(ex.getMessage());
+ } finally {
+ if (interpreter != null) {
+ interpreter.close();
+ }
+ }
+ }
+
+ // BAD: load arbitrary class file to execute
+ protected void doTrace(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ response.setContentType("text/plain");
+ String code = request.getParameter("code");
+ PythonInterpreter interpreter = null;
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+ try {
+ interpreter = new PythonInterpreter();
+ interpreter.setOut(out);
+ interpreter.setErr(out);
+
+ PyCode pyCode = BytecodeLoader.makeCode("test", code.getBytes(), getServletContext().getRealPath("/com/example/test.pyc"));
+ interpreter.exec(pyCode);
+ out.flush();
+
+ response.getWriter().print(out.toString());
+ } catch(PyException ex) {
+ response.getWriter().println(ex.getMessage());
+ } finally {
+ if (interpreter != null) {
+ interpreter.close();
+ }
+ }
+ }
+
+ // BAD: Compile Python code to execute
+ protected void doHead(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ response.setContentType("text/plain");
+ PythonInterpreter interpreter = null;
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+ try {
+ interpreter = new PythonInterpreter();
+ interpreter.setOut(out);
+ interpreter.setErr(out);
+
+ PyCode pyCode = Py.compile(request.getInputStream(), "Test.py", org.python.core.CompileMode.eval);
+ interpreter.exec(pyCode);
+ out.flush();
+
+ response.getWriter().print(out.toString());
+ } catch(PyException ex) {
+ response.getWriter().println(ex.getMessage());
+ } finally {
+ if (interpreter != null) {
+ interpreter.close();
+ }
+ }
+ }
+}
diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/JythonInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-094/JythonInjection.qlref
new file mode 100644
index 00000000000..0ba9fd60621
--- /dev/null
+++ b/java/ql/test/experimental/query-tests/security/CWE-094/JythonInjection.qlref
@@ -0,0 +1 @@
+experimental/Security/CWE/CWE-094/JythonInjection.ql
\ No newline at end of file
diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/RhinoServlet.java b/java/ql/test/experimental/query-tests/security/CWE-094/RhinoServlet.java
new file mode 100644
index 00000000000..e76a9543f87
--- /dev/null
+++ b/java/ql/test/experimental/query-tests/security/CWE-094/RhinoServlet.java
@@ -0,0 +1,91 @@
+import java.io.IOException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.mozilla.javascript.ClassShutter;
+import org.mozilla.javascript.CompilerEnvirons;
+import org.mozilla.javascript.Context;
+import org.mozilla.javascript.DefiningClassLoader;
+import org.mozilla.javascript.Scriptable;
+import org.mozilla.javascript.RhinoException;
+import org.mozilla.javascript.optimizer.ClassCompiler;
+
+/**
+ * Servlet implementation class RhinoServlet
+ */
+public class RhinoServlet extends HttpServlet {
+ private static final long serialVersionUID = 1L;
+
+ public RhinoServlet() {
+ super();
+ }
+
+ // BAD: allow arbitrary Java and JavaScript code to be executed
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ response.setContentType("text/plain");
+ String code = request.getParameter("code");
+ Context ctx = Context.enter();
+ try {
+ Scriptable scope = ctx.initStandardObjects();
+ Object result = ctx.evaluateString(scope, code, "", 1, null);
+ response.getWriter().print(Context.toString(result));
+ } catch(RhinoException ex) {
+ response.getWriter().println(ex.getMessage());
+ } finally {
+ Context.exit();
+ }
+ }
+
+ // GOOD: enable the safe mode
+ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ response.setContentType("text/plain");
+ String code = request.getParameter("code");
+ Context ctx = Context.enter();
+ try {
+ Scriptable scope = ctx.initSafeStandardObjects();
+ Object result = ctx.evaluateString(scope, code, "", 1, null);
+ response.getWriter().print(Context.toString(result));
+ } catch(RhinoException ex) {
+ response.getWriter().println(ex.getMessage());
+ } finally {
+ Context.exit();
+ }
+ }
+
+ // GOOD: enforce a constraint on allowed classes
+ protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ response.setContentType("text/plain");
+ String code = request.getParameter("code");
+ Context ctx = Context.enter();
+ try {
+ Scriptable scope = ctx.initStandardObjects();
+ ctx.setClassShutter(new ClassShutter() {
+ public boolean visibleToScripts(String className) {
+ return className.startsWith("com.example.");
+ }
+ });
+
+ Object result = ctx.evaluateString(scope, code, "", 1, null);
+ response.getWriter().print(Context.toString(result));
+ } catch(RhinoException ex) {
+ response.getWriter().println(ex.getMessage());
+ } finally {
+ Context.exit();
+ }
+ }
+
+ // BAD: allow arbitrary code to be compiled for subsequent execution
+ protected void doGet2(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ String code = request.getParameter("code");
+ ClassCompiler compiler = new ClassCompiler(new CompilerEnvirons());
+ Object[] objs = compiler.compileToClassFiles(code, "/sourceLocation", 1, "mainClassName");
+ }
+
+ // BAD: allow arbitrary code to be loaded for subsequent execution
+ protected void doPost2(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ String code = request.getParameter("code");
+ Class clazz = new DefiningClassLoader().defineClass("Powerfunc", code.getBytes());
+ }
+}
diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/ScriptEngine.expected b/java/ql/test/experimental/query-tests/security/CWE-094/ScriptEngine.expected
deleted file mode 100644
index a65faafc6bd..00000000000
--- a/java/ql/test/experimental/query-tests/security/CWE-094/ScriptEngine.expected
+++ /dev/null
@@ -1,32 +0,0 @@
-edges
-| ScriptEngineTest.java:8:44:8:55 | input : String | ScriptEngineTest.java:12:37:12:41 | input |
-| ScriptEngineTest.java:15:51:15:62 | input : String | ScriptEngineTest.java:19:31:19:35 | input |
-| ScriptEngineTest.java:23:58:23:69 | input : String | ScriptEngineTest.java:27:31:27:35 | input |
-| ScriptEngineTest.java:30:46:30:57 | input : String | ScriptEngineTest.java:34:31:34:35 | input |
-| ScriptEngineTest.java:37:26:37:38 | args : String[] | ScriptEngineTest.java:38:56:38:62 | ...[...] : String |
-| ScriptEngineTest.java:37:26:37:38 | args : String[] | ScriptEngineTest.java:39:63:39:69 | ...[...] : String |
-| ScriptEngineTest.java:37:26:37:38 | args : String[] | ScriptEngineTest.java:40:70:40:76 | ...[...] : String |
-| ScriptEngineTest.java:37:26:37:38 | args : String[] | ScriptEngineTest.java:41:58:41:64 | ...[...] : String |
-| ScriptEngineTest.java:38:56:38:62 | ...[...] : String | ScriptEngineTest.java:8:44:8:55 | input : String |
-| ScriptEngineTest.java:39:63:39:69 | ...[...] : String | ScriptEngineTest.java:15:51:15:62 | input : String |
-| ScriptEngineTest.java:40:70:40:76 | ...[...] : String | ScriptEngineTest.java:23:58:23:69 | input : String |
-| ScriptEngineTest.java:41:58:41:64 | ...[...] : String | ScriptEngineTest.java:30:46:30:57 | input : String |
-nodes
-| ScriptEngineTest.java:8:44:8:55 | input : String | semmle.label | input : String |
-| ScriptEngineTest.java:12:37:12:41 | input | semmle.label | input |
-| ScriptEngineTest.java:15:51:15:62 | input : String | semmle.label | input : String |
-| ScriptEngineTest.java:19:31:19:35 | input | semmle.label | input |
-| ScriptEngineTest.java:23:58:23:69 | input : String | semmle.label | input : String |
-| ScriptEngineTest.java:27:31:27:35 | input | semmle.label | input |
-| ScriptEngineTest.java:30:46:30:57 | input : String | semmle.label | input : String |
-| ScriptEngineTest.java:34:31:34:35 | input | semmle.label | input |
-| ScriptEngineTest.java:37:26:37:38 | args : String[] | semmle.label | args : String[] |
-| ScriptEngineTest.java:38:56:38:62 | ...[...] : String | semmle.label | ...[...] : String |
-| ScriptEngineTest.java:39:63:39:69 | ...[...] : String | semmle.label | ...[...] : String |
-| ScriptEngineTest.java:40:70:40:76 | ...[...] : String | semmle.label | ...[...] : String |
-| ScriptEngineTest.java:41:58:41:64 | ...[...] : String | semmle.label | ...[...] : String |
-#select
-| ScriptEngineTest.java:12:19:12:42 | eval(...) | ScriptEngineTest.java:37:26:37:38 | args : String[] | ScriptEngineTest.java:12:37:12:41 | input | ScriptEngine eval $@. | ScriptEngineTest.java:37:26:37:38 | args | user input |
-| ScriptEngineTest.java:19:19:19:36 | eval(...) | ScriptEngineTest.java:37:26:37:38 | args : String[] | ScriptEngineTest.java:19:31:19:35 | input | ScriptEngine eval $@. | ScriptEngineTest.java:37:26:37:38 | args | user input |
-| ScriptEngineTest.java:27:19:27:36 | eval(...) | ScriptEngineTest.java:37:26:37:38 | args : String[] | ScriptEngineTest.java:27:31:27:35 | input | ScriptEngine eval $@. | ScriptEngineTest.java:37:26:37:38 | args | user input |
-| ScriptEngineTest.java:34:19:34:36 | eval(...) | ScriptEngineTest.java:37:26:37:38 | args : String[] | ScriptEngineTest.java:34:31:34:35 | input | ScriptEngine eval $@. | ScriptEngineTest.java:37:26:37:38 | args | user input |
diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/ScriptEngine.qlref b/java/ql/test/experimental/query-tests/security/CWE-094/ScriptEngine.qlref
deleted file mode 100644
index 9566c986778..00000000000
--- a/java/ql/test/experimental/query-tests/security/CWE-094/ScriptEngine.qlref
+++ /dev/null
@@ -1 +0,0 @@
-experimental/Security/CWE/CWE-094/ScriptEngine.ql
diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/ScriptEngineTest.java b/java/ql/test/experimental/query-tests/security/CWE-094/ScriptEngineTest.java
index e04ec615f30..ed7099d7598 100755
--- a/java/ql/test/experimental/query-tests/security/CWE-094/ScriptEngineTest.java
+++ b/java/ql/test/experimental/query-tests/security/CWE-094/ScriptEngineTest.java
@@ -1,9 +1,21 @@
+import javax.script.AbstractScriptEngine;
+import javax.script.Compilable;
+import javax.script.CompiledScript;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptEngineFactory;
+import javax.script.ScriptException;
+
import jdk.nashorn.api.scripting.NashornScriptEngine;
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
-import javax.script.*;
+import java.io.IOException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
-public class ScriptEngineTest {
+public class ScriptEngineTest extends HttpServlet {
public void testWithScriptEngineReference(String input) throws ScriptException {
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
@@ -33,26 +45,59 @@ public class ScriptEngineTest {
MyCustomScriptEngine engine = (MyCustomScriptEngine) factory.getScriptEngine(new String[] { "-scripting" });
Object result = engine.eval(input);
}
-
- public static void main(String[] args) throws ScriptException {
- new ScriptEngineTest().testWithScriptEngineReference(args[0]);
- new ScriptEngineTest().testNashornWithScriptEngineReference(args[0]);
- new ScriptEngineTest().testNashornWithNashornScriptEngineReference(args[0]);
- new ScriptEngineTest().testCustomScriptEngineReference(args[0]);
+
+ public void testScriptEngineCompilable(String input) throws ScriptException {
+ NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
+ Compilable engine = (Compilable) factory.getScriptEngine(new String[] { "-scripting" });
+ CompiledScript script = engine.compile(input);
+ Object result = script.eval();
}
-
+
+ public void testScriptEngineGetProgram(String input) throws ScriptException {
+ ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
+ ScriptEngine engine = scriptEngineManager.getEngineByName("nashorn");
+ String program = engine.getFactory().getProgram(input);
+ Object result = engine.eval(program);
+ }
+
private static class MyCustomScriptEngine extends AbstractScriptEngine {
- public Object eval(String var1) throws ScriptException {
- return null;
- }
+ public Object eval(String var1) throws ScriptException { return null; }
+
+ @Override
+ public ScriptEngineFactory getFactory() { return null; }
}
private static class MyCustomFactory implements ScriptEngineFactory {
public MyCustomFactory() {
- }
-
- public ScriptEngine getScriptEngine() { return null; }
+ }
+
+ @Override
+ public ScriptEngine getScriptEngine() { return null; }
public ScriptEngine getScriptEngine(String... args) { return null; }
+
+ @Override
+ public String getEngineName() { return null; }
+
+ @Override
+ public String getMethodCallSyntax(final String obj, final String method, final String... args) { return null; }
+
+ @Override
+ public String getProgram(final String... statements) { return null; }
+ }
+
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ try {
+ String code = request.getParameter("code");
+
+ new ScriptEngineTest().testWithScriptEngineReference(code);
+ new ScriptEngineTest().testNashornWithScriptEngineReference(code);
+ new ScriptEngineTest().testNashornWithNashornScriptEngineReference(code);
+ new ScriptEngineTest().testCustomScriptEngineReference(code);
+ new ScriptEngineTest().testScriptEngineCompilable(code);
+ new ScriptEngineTest().testScriptEngineGetProgram(code);
+ } catch (ScriptException se) {
+ throw new IOException(se.getMessage());
+ }
}
}
diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/ScriptInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-094/ScriptInjection.expected
new file mode 100644
index 00000000000..5f1d250e9a2
--- /dev/null
+++ b/java/ql/test/experimental/query-tests/security/CWE-094/ScriptInjection.expected
@@ -0,0 +1,58 @@
+edges
+| RhinoServlet.java:28:23:28:50 | getParameter(...) : String | RhinoServlet.java:32:55:32:58 | code |
+| RhinoServlet.java:81:23:81:50 | getParameter(...) : String | RhinoServlet.java:83:54:83:57 | code |
+| RhinoServlet.java:88:23:88:50 | getParameter(...) : String | RhinoServlet.java:89:74:89:88 | getBytes(...) |
+| ScriptEngineTest.java:20:44:20:55 | input : String | ScriptEngineTest.java:24:37:24:41 | input |
+| ScriptEngineTest.java:27:51:27:62 | input : String | ScriptEngineTest.java:31:31:31:35 | input |
+| ScriptEngineTest.java:35:58:35:69 | input : String | ScriptEngineTest.java:39:31:39:35 | input |
+| ScriptEngineTest.java:42:46:42:57 | input : String | ScriptEngineTest.java:46:31:46:35 | input |
+| ScriptEngineTest.java:49:41:49:52 | input : String | ScriptEngineTest.java:52:42:52:46 | input |
+| ScriptEngineTest.java:56:41:56:52 | input : String | ScriptEngineTest.java:59:51:59:55 | input |
+| ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:93:57:93:60 | code : String |
+| ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:94:64:94:67 | code : String |
+| ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:95:71:95:74 | code : String |
+| ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:96:59:96:62 | code : String |
+| ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:97:54:97:57 | code : String |
+| ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:98:54:98:57 | code : String |
+| ScriptEngineTest.java:93:57:93:60 | code : String | ScriptEngineTest.java:20:44:20:55 | input : String |
+| ScriptEngineTest.java:94:64:94:67 | code : String | ScriptEngineTest.java:27:51:27:62 | input : String |
+| ScriptEngineTest.java:95:71:95:74 | code : String | ScriptEngineTest.java:35:58:35:69 | input : String |
+| ScriptEngineTest.java:96:59:96:62 | code : String | ScriptEngineTest.java:42:46:42:57 | input : String |
+| ScriptEngineTest.java:97:54:97:57 | code : String | ScriptEngineTest.java:49:41:49:52 | input : String |
+| ScriptEngineTest.java:98:54:98:57 | code : String | ScriptEngineTest.java:56:41:56:52 | input : String |
+nodes
+| RhinoServlet.java:28:23:28:50 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| RhinoServlet.java:32:55:32:58 | code | semmle.label | code |
+| RhinoServlet.java:81:23:81:50 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| RhinoServlet.java:83:54:83:57 | code | semmle.label | code |
+| RhinoServlet.java:88:23:88:50 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| RhinoServlet.java:89:74:89:88 | getBytes(...) | semmle.label | getBytes(...) |
+| ScriptEngineTest.java:20:44:20:55 | input : String | semmle.label | input : String |
+| ScriptEngineTest.java:24:37:24:41 | input | semmle.label | input |
+| ScriptEngineTest.java:27:51:27:62 | input : String | semmle.label | input : String |
+| ScriptEngineTest.java:31:31:31:35 | input | semmle.label | input |
+| ScriptEngineTest.java:35:58:35:69 | input : String | semmle.label | input : String |
+| ScriptEngineTest.java:39:31:39:35 | input | semmle.label | input |
+| ScriptEngineTest.java:42:46:42:57 | input : String | semmle.label | input : String |
+| ScriptEngineTest.java:46:31:46:35 | input | semmle.label | input |
+| ScriptEngineTest.java:49:41:49:52 | input : String | semmle.label | input : String |
+| ScriptEngineTest.java:52:42:52:46 | input | semmle.label | input |
+| ScriptEngineTest.java:56:41:56:52 | input : String | semmle.label | input : String |
+| ScriptEngineTest.java:59:51:59:55 | input | semmle.label | input |
+| ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| ScriptEngineTest.java:93:57:93:60 | code : String | semmle.label | code : String |
+| ScriptEngineTest.java:94:64:94:67 | code : String | semmle.label | code : String |
+| ScriptEngineTest.java:95:71:95:74 | code : String | semmle.label | code : String |
+| ScriptEngineTest.java:96:59:96:62 | code : String | semmle.label | code : String |
+| ScriptEngineTest.java:97:54:97:57 | code : String | semmle.label | code : String |
+| ScriptEngineTest.java:98:54:98:57 | code : String | semmle.label | code : String |
+#select
+| RhinoServlet.java:32:29:32:78 | evaluateString(...) | RhinoServlet.java:28:23:28:50 | getParameter(...) : String | RhinoServlet.java:32:55:32:58 | code | Java Script Engine evaluate $@. | RhinoServlet.java:28:23:28:50 | getParameter(...) | user input |
+| RhinoServlet.java:83:25:83:97 | compileToClassFiles(...) | RhinoServlet.java:81:23:81:50 | getParameter(...) : String | RhinoServlet.java:83:54:83:57 | code | Java Script Engine evaluate $@. | RhinoServlet.java:81:23:81:50 | getParameter(...) | user input |
+| RhinoServlet.java:89:23:89:89 | defineClass(...) | RhinoServlet.java:88:23:88:50 | getParameter(...) : String | RhinoServlet.java:89:74:89:88 | getBytes(...) | Java Script Engine evaluate $@. | RhinoServlet.java:88:23:88:50 | getParameter(...) | user input |
+| ScriptEngineTest.java:24:19:24:42 | eval(...) | ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:24:37:24:41 | input | Java Script Engine evaluate $@. | ScriptEngineTest.java:91:18:91:45 | getParameter(...) | user input |
+| ScriptEngineTest.java:31:19:31:36 | eval(...) | ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:31:31:31:35 | input | Java Script Engine evaluate $@. | ScriptEngineTest.java:91:18:91:45 | getParameter(...) | user input |
+| ScriptEngineTest.java:39:19:39:36 | eval(...) | ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:39:31:39:35 | input | Java Script Engine evaluate $@. | ScriptEngineTest.java:91:18:91:45 | getParameter(...) | user input |
+| ScriptEngineTest.java:46:19:46:36 | eval(...) | ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:46:31:46:35 | input | Java Script Engine evaluate $@. | ScriptEngineTest.java:91:18:91:45 | getParameter(...) | user input |
+| ScriptEngineTest.java:52:27:52:47 | compile(...) | ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:52:42:52:46 | input | Java Script Engine evaluate $@. | ScriptEngineTest.java:91:18:91:45 | getParameter(...) | user input |
+| ScriptEngineTest.java:59:20:59:56 | getProgram(...) | ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:59:51:59:55 | input | Java Script Engine evaluate $@. | ScriptEngineTest.java:91:18:91:45 | getParameter(...) | user input |
diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/ScriptInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-094/ScriptInjection.qlref
new file mode 100644
index 00000000000..da2b4287d0c
--- /dev/null
+++ b/java/ql/test/experimental/query-tests/security/CWE-094/ScriptInjection.qlref
@@ -0,0 +1 @@
+experimental/Security/CWE/CWE-094/ScriptInjection.ql
\ No newline at end of file
diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/options b/java/ql/test/experimental/query-tests/security/CWE-094/options
index 18e3518fc97..48cc00e0a17 100644
--- a/java/ql/test/experimental/query-tests/security/CWE-094/options
+++ b/java/ql/test/experimental/query-tests/security/CWE-094/options
@@ -1,2 +1,2 @@
-//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../../stubs/mvel2-2.4.7:${testdir}/../../../../stubs/jsr223-api:${testdir}/../../../../stubs/apache-commons-jexl-2.1.1:${testdir}/../../../../stubs/apache-commons-jexl-3.1:${testdir}/../../../../stubs/scriptengine:${testdir}/../../../../stubs/java-ee-el:${testdir}/../../../../stubs/juel-2.2:${testdir}/../../../stubs/groovy-all-3.0.7:${testdir}/../../../../stubs/servlet-api-2.4
+//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../../stubs/mvel2-2.4.7:${testdir}/../../../../stubs/jsr223-api:${testdir}/../../../../stubs/apache-commons-jexl-2.1.1:${testdir}/../../../../stubs/apache-commons-jexl-3.1:${testdir}/../../../../stubs/scriptengine:${testdir}/../../../../stubs/java-ee-el:${testdir}/../../../../stubs/juel-2.2:${testdir}/../../../stubs/groovy-all-3.0.7:${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/jython-2.7.2:${testdir}/../../../../experimental/stubs/rhino-1.7.13
diff --git a/java/ql/test/experimental/query-tests/security/CWE-601/SpringUrlRedirect.expected b/java/ql/test/experimental/query-tests/security/CWE-601/SpringUrlRedirect.expected
new file mode 100644
index 00000000000..bcf5e892e1b
--- /dev/null
+++ b/java/ql/test/experimental/query-tests/security/CWE-601/SpringUrlRedirect.expected
@@ -0,0 +1,35 @@
+edges
+| SpringUrlRedirect.java:13:30:13:47 | redirectUrl : String | SpringUrlRedirect.java:15:19:15:29 | redirectUrl |
+| SpringUrlRedirect.java:20:24:20:41 | redirectUrl : String | SpringUrlRedirect.java:21:36:21:46 | redirectUrl |
+| SpringUrlRedirect.java:26:30:26:47 | redirectUrl : String | SpringUrlRedirect.java:27:44:27:54 | redirectUrl |
+| SpringUrlRedirect.java:32:30:32:47 | redirectUrl : String | SpringUrlRedirect.java:33:47:33:57 | redirectUrl |
+| SpringUrlRedirect.java:37:24:37:41 | redirectUrl : String | SpringUrlRedirect.java:40:29:40:39 | redirectUrl |
+| SpringUrlRedirect.java:45:24:45:41 | redirectUrl : String | SpringUrlRedirect.java:48:30:48:40 | redirectUrl |
+| SpringUrlRedirect.java:53:24:53:41 | redirectUrl : String | SpringUrlRedirect.java:54:30:54:66 | format(...) |
+| SpringUrlRedirect.java:58:24:58:41 | redirectUrl : String | SpringUrlRedirect.java:59:30:59:76 | format(...) |
+nodes
+| SpringUrlRedirect.java:13:30:13:47 | redirectUrl : String | semmle.label | redirectUrl : String |
+| SpringUrlRedirect.java:15:19:15:29 | redirectUrl | semmle.label | redirectUrl |
+| SpringUrlRedirect.java:20:24:20:41 | redirectUrl : String | semmle.label | redirectUrl : String |
+| SpringUrlRedirect.java:21:36:21:46 | redirectUrl | semmle.label | redirectUrl |
+| SpringUrlRedirect.java:26:30:26:47 | redirectUrl : String | semmle.label | redirectUrl : String |
+| SpringUrlRedirect.java:27:44:27:54 | redirectUrl | semmle.label | redirectUrl |
+| SpringUrlRedirect.java:32:30:32:47 | redirectUrl : String | semmle.label | redirectUrl : String |
+| SpringUrlRedirect.java:33:47:33:57 | redirectUrl | semmle.label | redirectUrl |
+| SpringUrlRedirect.java:37:24:37:41 | redirectUrl : String | semmle.label | redirectUrl : String |
+| SpringUrlRedirect.java:40:29:40:39 | redirectUrl | semmle.label | redirectUrl |
+| SpringUrlRedirect.java:45:24:45:41 | redirectUrl : String | semmle.label | redirectUrl : String |
+| SpringUrlRedirect.java:48:30:48:40 | redirectUrl | semmle.label | redirectUrl |
+| SpringUrlRedirect.java:53:24:53:41 | redirectUrl : String | semmle.label | redirectUrl : String |
+| SpringUrlRedirect.java:54:30:54:66 | format(...) | semmle.label | format(...) |
+| SpringUrlRedirect.java:58:24:58:41 | redirectUrl : String | semmle.label | redirectUrl : String |
+| SpringUrlRedirect.java:59:30:59:76 | format(...) | semmle.label | format(...) |
+#select
+| SpringUrlRedirect.java:15:19:15:29 | redirectUrl | SpringUrlRedirect.java:13:30:13:47 | redirectUrl : String | SpringUrlRedirect.java:15:19:15:29 | redirectUrl | Potentially untrusted URL redirection due to $@. | SpringUrlRedirect.java:13:30:13:47 | redirectUrl | user-provided value |
+| SpringUrlRedirect.java:21:36:21:46 | redirectUrl | SpringUrlRedirect.java:20:24:20:41 | redirectUrl : String | SpringUrlRedirect.java:21:36:21:46 | redirectUrl | Potentially untrusted URL redirection due to $@. | SpringUrlRedirect.java:20:24:20:41 | redirectUrl | user-provided value |
+| SpringUrlRedirect.java:27:44:27:54 | redirectUrl | SpringUrlRedirect.java:26:30:26:47 | redirectUrl : String | SpringUrlRedirect.java:27:44:27:54 | redirectUrl | Potentially untrusted URL redirection due to $@. | SpringUrlRedirect.java:26:30:26:47 | redirectUrl | user-provided value |
+| SpringUrlRedirect.java:33:47:33:57 | redirectUrl | SpringUrlRedirect.java:32:30:32:47 | redirectUrl : String | SpringUrlRedirect.java:33:47:33:57 | redirectUrl | Potentially untrusted URL redirection due to $@. | SpringUrlRedirect.java:32:30:32:47 | redirectUrl | user-provided value |
+| SpringUrlRedirect.java:40:29:40:39 | redirectUrl | SpringUrlRedirect.java:37:24:37:41 | redirectUrl : String | SpringUrlRedirect.java:40:29:40:39 | redirectUrl | Potentially untrusted URL redirection due to $@. | SpringUrlRedirect.java:37:24:37:41 | redirectUrl | user-provided value |
+| SpringUrlRedirect.java:48:30:48:40 | redirectUrl | SpringUrlRedirect.java:45:24:45:41 | redirectUrl : String | SpringUrlRedirect.java:48:30:48:40 | redirectUrl | Potentially untrusted URL redirection due to $@. | SpringUrlRedirect.java:45:24:45:41 | redirectUrl | user-provided value |
+| SpringUrlRedirect.java:54:30:54:66 | format(...) | SpringUrlRedirect.java:53:24:53:41 | redirectUrl : String | SpringUrlRedirect.java:54:30:54:66 | format(...) | Potentially untrusted URL redirection due to $@. | SpringUrlRedirect.java:53:24:53:41 | redirectUrl | user-provided value |
+| SpringUrlRedirect.java:59:30:59:76 | format(...) | SpringUrlRedirect.java:58:24:58:41 | redirectUrl : String | SpringUrlRedirect.java:59:30:59:76 | format(...) | Potentially untrusted URL redirection due to $@. | SpringUrlRedirect.java:58:24:58:41 | redirectUrl | user-provided value |
diff --git a/java/ql/test/experimental/query-tests/security/CWE-601/SpringUrlRedirect.java b/java/ql/test/experimental/query-tests/security/CWE-601/SpringUrlRedirect.java
new file mode 100644
index 00000000000..f3958cba102
--- /dev/null
+++ b/java/ql/test/experimental/query-tests/security/CWE-601/SpringUrlRedirect.java
@@ -0,0 +1,83 @@
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.view.RedirectView;
+
+@Controller
+public class SpringUrlRedirect {
+
+ private final static String VALID_REDIRECT = "http://127.0.0.1";
+
+ @GetMapping("url1")
+ public RedirectView bad1(String redirectUrl, HttpServletResponse response) throws Exception {
+ RedirectView rv = new RedirectView();
+ rv.setUrl(redirectUrl);
+ return rv;
+ }
+
+ @GetMapping("url2")
+ public String bad2(String redirectUrl) {
+ String url = "redirect:" + redirectUrl;
+ return url;
+ }
+
+ @GetMapping("url3")
+ public RedirectView bad3(String redirectUrl) {
+ RedirectView rv = new RedirectView(redirectUrl);
+ return rv;
+ }
+
+ @GetMapping("url4")
+ public ModelAndView bad4(String redirectUrl) {
+ return new ModelAndView("redirect:" + redirectUrl);
+ }
+
+ @GetMapping("url5")
+ public String bad5(String redirectUrl) {
+ StringBuffer stringBuffer = new StringBuffer();
+ stringBuffer.append("redirect:");
+ stringBuffer.append(redirectUrl);
+ return stringBuffer.toString();
+ }
+
+ @GetMapping("url6")
+ public String bad6(String redirectUrl) {
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append("redirect:");
+ stringBuilder.append(redirectUrl);
+ return stringBuilder.toString();
+ }
+
+ @GetMapping("url7")
+ public String bad7(String redirectUrl) {
+ return "redirect:" + String.format("%s/?aaa", redirectUrl);
+ }
+
+ @GetMapping("url8")
+ public String bad8(String redirectUrl, String token) {
+ return "redirect:" + String.format(redirectUrl + "?token=%s", token);
+ }
+
+ @GetMapping("url9")
+ public RedirectView good1(String redirectUrl) {
+ RedirectView rv = new RedirectView();
+ if (redirectUrl.startsWith(VALID_REDIRECT)){
+ rv.setUrl(redirectUrl);
+ }else {
+ rv.setUrl(VALID_REDIRECT);
+ }
+ return rv;
+ }
+
+ @GetMapping("url10")
+ public ModelAndView good2(String token) {
+ String url = "/edit?token=" + token;
+ return new ModelAndView("redirect:" + url);
+ }
+
+ @GetMapping("url11")
+ public String good3(String status) {
+ return "redirect:" + String.format("/stories/search/criteria?status=%s", status);
+ }
+}
diff --git a/java/ql/test/experimental/query-tests/security/CWE-601/SpringUrlRedirect.qlref b/java/ql/test/experimental/query-tests/security/CWE-601/SpringUrlRedirect.qlref
new file mode 100644
index 00000000000..418be1d307b
--- /dev/null
+++ b/java/ql/test/experimental/query-tests/security/CWE-601/SpringUrlRedirect.qlref
@@ -0,0 +1 @@
+experimental/Security/CWE/CWE-601/SpringUrlRedirect.ql
diff --git a/java/ql/test/experimental/query-tests/security/CWE-601/options b/java/ql/test/experimental/query-tests/security/CWE-601/options
new file mode 100644
index 00000000000..a9289108747
--- /dev/null
+++ b/java/ql/test/experimental/query-tests/security/CWE-601/options
@@ -0,0 +1 @@
+//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/springframework-5.2.3/
\ No newline at end of file
diff --git a/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/ClassShutter.java b/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/ClassShutter.java
new file mode 100644
index 00000000000..f425e08e966
--- /dev/null
+++ b/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/ClassShutter.java
@@ -0,0 +1,56 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// API class
+
+package org.mozilla.javascript;
+
+/**
+Embeddings that wish to filter Java classes that are visible to scripts
+through the LiveConnect, should implement this interface.
+
+@see Context#setClassShutter(ClassShutter)
+@since 1.5 Release 4
+@author Norris Boyd
+*/
+
+ public interface ClassShutter {
+
+ /**
+ * Return true iff the Java class with the given name should be exposed
+ * to scripts.
+ *
+ * An embedding may filter which Java classes are exposed through
+ * LiveConnect to JavaScript scripts.
+ *
+ * Due to the fact that there is no package reflection in Java,
+ * this method will also be called with package names. There
+ * is no way for Rhino to tell if "Packages.a.b" is a package name
+ * or a class that doesn't exist. What Rhino does is attempt
+ * to load each segment of "Packages.a.b.c": It first attempts to
+ * load class "a", then attempts to load class "a.b", then
+ * finally attempts to load class "a.b.c". On a Rhino installation
+ * without any ClassShutter set, and without any of the
+ * above classes, the expression "Packages.a.b.c" will result in
+ * a [JavaPackage a.b.c] and not an error.
+ *
+ * With ClassShutter supplied, Rhino will first call
+ * visibleToScripts before attempting to look up the class name. If
+ * visibleToScripts returns false, the class name lookup is not
+ * performed and subsequent Rhino execution assumes the class is
+ * not present. So for "java.lang.System.out.println" the lookup
+ * of "java.lang.System" is skipped and thus Rhino assumes that
+ * "java.lang.System" doesn't exist. So then for "java.lang.System.out",
+ * Rhino attempts to load the class "java.lang.System.out" because
+ * it assumes that "java.lang.System" is a package name.
+ *
+ * @param fullClassName the full name of the class (including the package
+ * name, with '.' as a delimiter). For example the
+ * standard string class is "java.lang.String"
+ * @return whether or not to reveal this class to scripts
+ */
+ public boolean visibleToScripts(String fullClassName);
+}
diff --git a/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/CompilerEnvirons.java b/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/CompilerEnvirons.java
new file mode 100644
index 00000000000..3cb0619499e
--- /dev/null
+++ b/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/CompilerEnvirons.java
@@ -0,0 +1,12 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+ package org.mozilla.javascript;
+
+ public class CompilerEnvirons {
+ public CompilerEnvirons() {
+ }
+ }
\ No newline at end of file
diff --git a/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/Context.java b/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/Context.java
new file mode 100644
index 00000000000..1bda212cfa4
--- /dev/null
+++ b/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/Context.java
@@ -0,0 +1,695 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// API class
+
+package org.mozilla.javascript;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Locale;
+
+/**
+ * This class represents the runtime context of an executing script.
+ *
+ * Before executing a script, an instance of Context must be created
+ * and associated with the thread that will be executing the script.
+ * The Context will be used to store information about the executing
+ * of the script such as the call stack. Contexts are associated with
+ * the current thread using the {@link #call(ContextAction)}
+ * or {@link #enter()} methods.
+ *
+ * Different forms of script execution are supported. Scripts may be
+ * evaluated from the source directly, or first compiled and then later
+ * executed. Interactive execution is also supported.
+ *
+ * Some aspects of script execution, such as type conversions and
+ * object creation, may be accessed directly through methods of
+ * Context.
+ *
+ * @see Scriptable
+ * @author Norris Boyd
+ * @author Brendan Eich
+ */
+
+public class Context
+ implements Closeable
+{
+ /**
+ * Creates a new Context. The context will be associated with the {@link
+ * ContextFactory#getGlobal() global context factory}.
+ *
+ * Note that the Context must be associated with a thread before
+ * it can be used to execute a script.
+ * @deprecated this constructor is deprecated because it creates a
+ * dependency on a static singleton context factory. Use
+ * {@link ContextFactory#enter()} or
+ * {@link ContextFactory#call(ContextAction)} instead. If you subclass
+ * this class, consider using {@link #Context(ContextFactory)} constructor
+ * instead in the subclasses' constructors.
+ */
+ @Deprecated
+ public Context()
+ {
+ }
+
+ /**
+ * Creates a new context. Provided as a preferred super constructor for
+ * subclasses in place of the deprecated default public constructor.
+ * @param factory the context factory associated with this context (most
+ * likely, the one that created the context). Can not be null. The context
+ * features are inherited from the factory, and the context will also
+ * otherwise use its factory's services.
+ * @throws IllegalArgumentException if factory parameter is null.
+ */
+ protected Context(ContextFactory factory)
+ {
+ }
+
+ /**
+ * Get the current Context.
+ *
+ * The current Context is per-thread; this method looks up
+ * the Context associated with the current thread.
+ *
+ * @return the Context associated with the current thread, or
+ * null if no context is associated with the current
+ * thread.
+ * @see ContextFactory#enterContext()
+ * @see ContextFactory#call(ContextAction)
+ */
+ public static Context getCurrentContext()
+ {
+ return null;
+ }
+
+ /**
+ * Same as calling {@link ContextFactory#enterContext()} on the global
+ * ContextFactory instance.
+ * @return a Context associated with the current thread
+ * @see #getCurrentContext()
+ * @see #exit()
+ * @see #call(ContextAction)
+ */
+ public static Context enter()
+ {
+ return null;
+ }
+
+ /**
+ * Get a Context associated with the current thread, using
+ * the given Context if need be.
+ *
+ * The same as enter() except that cx
+ * is associated with the current thread and returned if
+ * the current thread has no associated context and cx
+ * is not associated with any other thread.
+ * @param cx a Context to associate with the thread if possible
+ * @return a Context associated with the current thread
+ * @deprecated use {@link ContextFactory#enterContext(Context)} instead as
+ * this method relies on usage of a static singleton "global" ContextFactory.
+ * @see ContextFactory#enterContext(Context)
+ * @see ContextFactory#call(ContextAction)
+ */
+ @Deprecated
+ public static Context enter(Context cx)
+ {
+ return null;
+ }
+
+ static final Context enter(Context cx, ContextFactory factory)
+ {
+ return null;
+ }
+
+ /**
+ * Exit a block of code requiring a Context.
+ *
+ * Calling exit() will remove the association between
+ * the current thread and a Context if the prior call to
+ * {@link ContextFactory#enterContext()} on this thread newly associated a
+ * Context with this thread. Once the current thread no longer has an
+ * associated Context, it cannot be used to execute JavaScript until it is
+ * again associated with a Context.
+ * @see ContextFactory#enterContext()
+ */
+ public static void exit()
+ {
+ }
+
+ @Override
+ public void close() {
+ }
+
+ /**
+ * Return {@link ContextFactory} instance used to create this Context.
+ */
+ public final ContextFactory getFactory()
+ {
+ return null;
+ }
+
+ /**
+ * Checks if this is a sealed Context. A sealed Context instance does not
+ * allow to modify any of its properties and will throw an exception
+ * on any such attempt.
+ * @see #seal(Object sealKey)
+ */
+ public final boolean isSealed()
+ {
+ return false;
+ }
+
+ /**
+ * Seal this Context object so any attempt to modify any of its properties
+ * including calling {@link #enter()} and {@link #exit()} methods will
+ * throw an exception.
+ *
+ * If sealKey is not null, calling
+ * {@link #unseal(Object sealKey)} with the same key unseals
+ * the object. If sealKey is null, unsealing is no longer possible.
+ *
+ * @see #isSealed()
+ * @see #unseal(Object)
+ */
+ public final void seal(Object sealKey)
+ {
+ }
+
+ /**
+ * Unseal previously sealed Context object.
+ * The sealKey argument should not be null and should match
+ * sealKey suplied with the last call to
+ * {@link #seal(Object)} or an exception will be thrown.
+ *
+ * @see #isSealed()
+ * @see #seal(Object sealKey)
+ */
+ public final void unseal(Object sealKey)
+ {
+ }
+
+ /**
+ * Get the current language version.
+ *
+ * The language version number affects JavaScript semantics as detailed
+ * in the overview documentation.
+ *
+ * @return an integer that is one of VERSION_1_0, VERSION_1_1, etc.
+ */
+ public final int getLanguageVersion()
+ {
+ return -1;
+ }
+
+ /**
+ * Set the language version.
+ *
+ *
+ * Setting the language version will affect functions and scripts compiled
+ * subsequently. See the overview documentation for version-specific
+ * behavior.
+ *
+ * @param version the version as specified by VERSION_1_0, VERSION_1_1, etc.
+ */
+ public void setLanguageVersion(int version)
+ {
+ }
+
+ public static boolean isValidLanguageVersion(int version)
+ {
+ return false;
+ }
+
+ public static void checkLanguageVersion(int version)
+ {
+ }
+
+ /**
+ * Get the implementation version.
+ *
+ *
+ * The implementation version is of the form
+ *
+ * "name langVer release relNum date"
+ *
+ * where name is the name of the product, langVer is
+ * the language version, relNum is the release number, and
+ * date is the release date for that specific
+ * release in the form "yyyy mm dd".
+ *
+ * @return a string that encodes the product, language version, release
+ * number, and date.
+ */
+ public final String getImplementationVersion() {
+ return null;
+ }
+
+ /**
+ * Initialize the standard objects.
+ *
+ * Creates instances of the standard objects and their constructors
+ * (Object, String, Number, Date, etc.), setting up 'scope' to act
+ * as a global object as in ECMA 15.1.
+ *
+ * This method must be called to initialize a scope before scripts
+ * can be evaluated in that scope.
+ *
+ * This method does not affect the Context it is called upon.
+ *
+ * @return the initialized scope
+ */
+ public final ScriptableObject initStandardObjects()
+ {
+ return null;
+ }
+
+ /**
+ * Initialize the standard objects, leaving out those that offer access directly
+ * to Java classes. This sets up "scope" to have access to all the standard
+ * JavaScript classes, but does not create global objects for any top-level
+ * Java packages. In addition, the "Packages," "JavaAdapter," and
+ * "JavaImporter" classes, and the "getClass" function, are not
+ * initialized.
+ *
+ * The result of this function is a scope that may be safely used in a "sandbox"
+ * environment where it is not desirable to give access to Java code from JavaScript.
+ *
+ * Creates instances of the standard objects and their constructors
+ * (Object, String, Number, Date, etc.), setting up 'scope' to act
+ * as a global object as in ECMA 15.1.
+ *
+ * This method must be called to initialize a scope before scripts
+ * can be evaluated in that scope.
+ *
+ * This method does not affect the Context it is called upon.
+ *
+ * @return the initialized scope
+ */
+ public final ScriptableObject initSafeStandardObjects()
+ {
+ return null;
+ }
+
+ /**
+ * Initialize the standard objects.
+ *
+ * Creates instances of the standard objects and their constructors
+ * (Object, String, Number, Date, etc.), setting up 'scope' to act
+ * as a global object as in ECMA 15.1.
+ *
+ * This method must be called to initialize a scope before scripts
+ * can be evaluated in that scope.
+ *
+ * This method does not affect the Context it is called upon.
+ *
+ * @param scope the scope to initialize, or null, in which case a new
+ * object will be created to serve as the scope
+ * @return the initialized scope. The method returns the value of the scope
+ * argument if it is not null or newly allocated scope object which
+ * is an instance {@link ScriptableObject}.
+ */
+ public final Scriptable initStandardObjects(ScriptableObject scope)
+ {
+ return null;
+ }
+
+ /**
+ * Initialize the standard objects, leaving out those that offer access directly
+ * to Java classes. This sets up "scope" to have access to all the standard
+ * JavaScript classes, but does not create global objects for any top-level
+ * Java packages. In addition, the "Packages," "JavaAdapter," and
+ * "JavaImporter" classes, and the "getClass" function, are not
+ * initialized.
+ *
+ * The result of this function is a scope that may be safely used in a "sandbox"
+ * environment where it is not desirable to give access to Java code from JavaScript.
+ *
+ * Creates instances of the standard objects and their constructors
+ * (Object, String, Number, Date, etc.), setting up 'scope' to act
+ * as a global object as in ECMA 15.1.
+ *
+ * This method must be called to initialize a scope before scripts
+ * can be evaluated in that scope.
+ *
+ * This method does not affect the Context it is called upon.
+ *
+ * @param scope the scope to initialize, or null, in which case a new
+ * object will be created to serve as the scope
+ * @return the initialized scope. The method returns the value of the scope
+ * argument if it is not null or newly allocated scope object which
+ * is an instance {@link ScriptableObject}.
+ */
+ public final Scriptable initSafeStandardObjects(ScriptableObject scope)
+ {
+ return null;
+ }
+
+ /**
+ * Initialize the standard objects.
+ *
+ * Creates instances of the standard objects and their constructors
+ * (Object, String, Number, Date, etc.), setting up 'scope' to act
+ * as a global object as in ECMA 15.1.
+ *
+ * This method must be called to initialize a scope before scripts
+ * can be evaluated in that scope.
+ *
+ * This method does not affect the Context it is called upon.
+ *
+ * This form of the method also allows for creating "sealed" standard
+ * objects. An object that is sealed cannot have properties added, changed,
+ * or removed. This is useful to create a "superglobal" that can be shared
+ * among several top-level objects. Note that sealing is not allowed in
+ * the current ECMA/ISO language specification, but is likely for
+ * the next version.
+ *
+ * @param scope the scope to initialize, or null, in which case a new
+ * object will be created to serve as the scope
+ * @param sealed whether or not to create sealed standard objects that
+ * cannot be modified.
+ * @return the initialized scope. The method returns the value of the scope
+ * argument if it is not null or newly allocated scope object.
+ * @since 1.4R3
+ */
+ public ScriptableObject initStandardObjects(ScriptableObject scope,
+ boolean sealed)
+ {
+ return null;
+ }
+
+ /**
+ * Initialize the standard objects, leaving out those that offer access directly
+ * to Java classes. This sets up "scope" to have access to all the standard
+ * JavaScript classes, but does not create global objects for any top-level
+ * Java packages. In addition, the "Packages," "JavaAdapter," and
+ * "JavaImporter" classes, and the "getClass" function, are not
+ * initialized.
+ *
+ * The result of this function is a scope that may be safely used in a "sandbox"
+ * environment where it is not desirable to give access to Java code from JavaScript.
+ *
+ * Creates instances of the standard objects and their constructors
+ * (Object, String, Number, Date, etc.), setting up 'scope' to act
+ * as a global object as in ECMA 15.1.
+ *
+ * This method must be called to initialize a scope before scripts
+ * can be evaluated in that scope.
+ *
+ * This method does not affect the Context it is called upon.
+ *
+ * This form of the method also allows for creating "sealed" standard
+ * objects. An object that is sealed cannot have properties added, changed,
+ * or removed. This is useful to create a "superglobal" that can be shared
+ * among several top-level objects. Note that sealing is not allowed in
+ * the current ECMA/ISO language specification, but is likely for
+ * the next version.
+ *
+ * @param scope the scope to initialize, or null, in which case a new
+ * object will be created to serve as the scope
+ * @param sealed whether or not to create sealed standard objects that
+ * cannot be modified.
+ * @return the initialized scope. The method returns the value of the scope
+ * argument if it is not null or newly allocated scope object.
+ * @since 1.7.6
+ */
+ public ScriptableObject initSafeStandardObjects(ScriptableObject scope,
+ boolean sealed)
+ {
+ return null;
+ }
+
+ /**
+ * Get the singleton object that represents the JavaScript Undefined value.
+ */
+ public static Object getUndefinedValue()
+ {
+ return null;
+ }
+
+ /**
+ * Evaluate a JavaScript source string.
+ *
+ * The provided source name and line number are used for error messages
+ * and for producing debug information.
+ *
+ * @param scope the scope to execute in
+ * @param source the JavaScript source
+ * @param sourceName a string describing the source, such as a filename
+ * @param lineno the starting line number
+ * @param securityDomain an arbitrary object that specifies security
+ * information about the origin or owner of the script. For
+ * implementations that don't care about security, this value
+ * may be null.
+ * @return the result of evaluating the string
+ * @see org.mozilla.javascript.SecurityController
+ */
+ public final Object evaluateString(Scriptable scope, String source,
+ String sourceName, int lineno,
+ Object securityDomain)
+ {
+ return null;
+ }
+
+ /**
+ * Evaluate a reader as JavaScript source.
+ *
+ * All characters of the reader are consumed.
+ *
+ * @param scope the scope to execute in
+ * @param in the Reader to get JavaScript source from
+ * @param sourceName a string describing the source, such as a filename
+ * @param lineno the starting line number
+ * @param securityDomain an arbitrary object that specifies security
+ * information about the origin or owner of the script. For
+ * implementations that don't care about security, this value
+ * may be null.
+ * @return the result of evaluating the source
+ *
+ * @exception IOException if an IOException was generated by the Reader
+ */
+ public final Object evaluateReader(Scriptable scope, Reader in,
+ String sourceName, int lineno,
+ Object securityDomain)
+ throws IOException
+ {
+ return null;
+ }
+
+ /**
+ * @deprecated
+ * @see #compileReader(Reader in, String sourceName, int lineno, Object securityDomain)
+ */
+ @Deprecated
+ public final Script compileReader(
+ Scriptable scope, Reader in, String sourceName, int lineno, Object securityDomain)
+ throws IOException {
+ return null;
+ }
+
+ /**
+ * Compiles the source in the given reader.
+ *
+ *
Returns a script that may later be executed. Will consume all the source in the reader.
+ *
+ * @param in the input reader
+ * @param sourceName a string describing the source, such as a filename
+ * @param lineno the starting line number for reporting errors
+ * @param securityDomain an arbitrary object that specifies security information about the
+ * origin or owner of the script. For implementations that don't care about security, this
+ * value may be null.
+ * @return a script that may later be executed
+ * @exception IOException if an IOException was generated by the Reader
+ * @see org.mozilla.javascript.Script
+ */
+ public final Script compileReader(
+ Reader in, String sourceName, int lineno, Object securityDomain) throws IOException {
+ return null;
+ }
+
+ /**
+ * Compiles the source in the given string.
+ *
+ *
Returns a script that may later be executed.
+ *
+ * @param source the source string
+ * @param sourceName a string describing the source, such as a filename
+ * @param lineno the starting line number for reporting errors. Use 0 if the line number is
+ * unknown.
+ * @param securityDomain an arbitrary object that specifies security information about the
+ * origin or owner of the script. For implementations that don't care about security, this
+ * value may be null.
+ * @return a script that may later be executed
+ * @see org.mozilla.javascript.Script
+ */
+ public final Script compileString(
+ String source, String sourceName, int lineno, Object securityDomain) {
+ return null;
+ }
+
+ /**
+ * Compile a JavaScript function.
+ *
+ *
The function source must be a function definition as defined by ECMA (e.g., "function f(a)
+ * { return a; }").
+ *
+ * @param scope the scope to compile relative to
+ * @param source the function definition source
+ * @param sourceName a string describing the source, such as a filename
+ * @param lineno the starting line number
+ * @param securityDomain an arbitrary object that specifies security information about the
+ * origin or owner of the script. For implementations that don't care about security, this
+ * value may be null.
+ * @return a Function that may later be called
+ * @see org.mozilla.javascript.Function
+ */
+ public final Function compileFunction(
+ Scriptable scope, String source, String sourceName, int lineno, Object securityDomain) {
+ return null;
+ }
+
+ /**
+ * Convert the value to a JavaScript boolean value.
+ *
+ * See ECMA 9.2.
+ *
+ * @param value a JavaScript value
+ * @return the corresponding boolean value converted using
+ * the ECMA rules
+ */
+ public static boolean toBoolean(Object value)
+ {
+ return false;
+ }
+
+ /**
+ * Convert the value to a JavaScript Number value.
+ *
+ * Returns a Java double for the JavaScript Number.
+ *
+ * See ECMA 9.3.
+ *
+ * @param value a JavaScript value
+ * @return the corresponding double value converted using
+ * the ECMA rules
+ */
+ public static double toNumber(Object value)
+ {
+ return -1;
+ }
+
+ /**
+ * Convert the value to a JavaScript String value.
+ *
+ * See ECMA 9.8.
+ *
+ * @param value a JavaScript value
+ * @return the corresponding String value converted using
+ * the ECMA rules
+ */
+ public static String toString(Object value)
+ {
+ return null;
+ }
+
+ /**
+ * Convert the value to an JavaScript object value.
+ *
+ * Note that a scope must be provided to look up the constructors
+ * for Number, Boolean, and String.
+ *
+ * See ECMA 9.9.
+ *
+ * Additionally, arbitrary Java objects and classes will be
+ * wrapped in a Scriptable object with its Java fields and methods
+ * reflected as JavaScript properties of the object.
+ *
+ * @param value any Java object
+ * @param scope global scope containing constructors for Number,
+ * Boolean, and String
+ * @return new JavaScript object
+ */
+ public static Scriptable toObject(Object value, Scriptable scope)
+ {
+ return null;
+ }
+
+ /**
+ * Convenient method to convert java value to its closest representation
+ * in JavaScript.
+ *
+ * If value is an instance of String, Number, Boolean, Function or
+ * Scriptable, it is returned as it and will be treated as the corresponding
+ * JavaScript type of string, number, boolean, function and object.
+ *
+ * Note that for Number instances during any arithmetic operation in
+ * JavaScript the engine will always use the result of
+ * Number.doubleValue() resulting in a precision loss if
+ * the number can not fit into double.
+ *
+ * If value is an instance of Character, it will be converted to string of
+ * length 1 and its JavaScript type will be string.
+ *
+ * The rest of values will be wrapped as LiveConnect objects
+ * by calling {@link WrapFactory#wrap(Context cx, Scriptable scope,
+ * Object obj, Class staticType)} as in:
+ *
+ * Context cx = Context.getCurrentContext();
+ * return cx.getWrapFactory().wrap(cx, scope, value, null);
+ *
+ *
+ * @param value any Java object
+ * @param scope top scope object
+ * @return value suitable to pass to any API that takes JavaScript values.
+ */
+ public static Object javaToJS(Object value, Scriptable scope)
+ {
+ return null;
+ }
+
+ /**
+ * Convert a JavaScript value into the desired type.
+ * Uses the semantics defined with LiveConnect3 and throws an
+ * Illegal argument exception if the conversion cannot be performed.
+ * @param value the JavaScript value to convert
+ * @param desiredType the Java type to convert to. Primitive Java
+ * types are represented using the TYPE fields in the corresponding
+ * wrapper class in java.lang.
+ * @return the converted value
+ * @throws EvaluatorException if the conversion cannot be performed
+ */
+ public static Object jsToJava(Object value, Class> desiredType)
+ {
+ return null;
+ }
+
+ /**
+ * Set the LiveConnect access filter for this context.
+ * {@link ClassShutter} may only be set if it is currently null.
+ * Otherwise a SecurityException is thrown.
+ * @param shutter a ClassShutter object
+ * @throws SecurityException if there is already a ClassShutter
+ * object for this Context
+ */
+ public synchronized final void setClassShutter(ClassShutter shutter)
+ {
+ }
+
+ final synchronized ClassShutter getClassShutter()
+ {
+ return null;
+ }
+
+ public interface ClassShutterSetter {
+ public void setClassShutter(ClassShutter shutter);
+ public ClassShutter getClassShutter();
+ }
+
+ public final synchronized ClassShutterSetter getClassShutterSetter() {
+ return null;
+ }
+}
diff --git a/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/ContextFactory.java b/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/ContextFactory.java
new file mode 100644
index 00000000000..a7f83f2095d
--- /dev/null
+++ b/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/ContextFactory.java
@@ -0,0 +1,314 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// API class
+
+package org.mozilla.javascript;
+
+/**
+ * Factory class that Rhino runtime uses to create new {@link Context}
+ * instances. A ContextFactory can also notify listeners
+ * about context creation and release.
+ *
+ * When the Rhino runtime needs to create new {@link Context} instance during
+ * execution of {@link Context#enter()} or {@link Context}, it will call
+ * {@link #makeContext()} of the current global ContextFactory.
+ * See {@link #getGlobal()} and {@link #initGlobal(ContextFactory)}.
+ *
+ * It is also possible to use explicit ContextFactory instances for Context
+ * creation. This is useful to have a set of independent Rhino runtime
+ * instances under single JVM. See {@link #call(ContextAction)}.
+ *
+ * The following example demonstrates Context customization to terminate
+ * scripts running more then 10 seconds and to provide better compatibility
+ * with JavaScript code using MSIE-specific features.
+ *
+ * import org.mozilla.javascript.*;
+ *
+ * class MyFactory extends ContextFactory
+ * {
+ *
+ * // Custom {@link Context} to store execution time.
+ * private static class MyContext extends Context
+ * {
+ * long startTime;
+ * }
+ *
+ * static {
+ * // Initialize GlobalFactory with custom factory
+ * ContextFactory.initGlobal(new MyFactory());
+ * }
+ *
+ * // Override {@link #makeContext()}
+ * protected Context makeContext()
+ * {
+ * MyContext cx = new MyContext();
+ * // Make Rhino runtime to call observeInstructionCount
+ * // each 10000 bytecode instructions
+ * cx.setInstructionObserverThreshold(10000);
+ * return cx;
+ * }
+ *
+ * // Override {@link #hasFeature(Context, int)}
+ * public boolean hasFeature(Context cx, int featureIndex)
+ * {
+ * // Turn on maximum compatibility with MSIE scripts
+ * switch (featureIndex) {
+ * case {@link Context#FEATURE_NON_ECMA_GET_YEAR}:
+ * return true;
+ *
+ * case {@link Context#FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME}:
+ * return true;
+ *
+ * case {@link Context#FEATURE_RESERVED_KEYWORD_AS_IDENTIFIER}:
+ * return true;
+ *
+ * case {@link Context#FEATURE_PARENT_PROTO_PROPERTIES}:
+ * return false;
+ * }
+ * return super.hasFeature(cx, featureIndex);
+ * }
+ *
+ * // Override {@link #observeInstructionCount(Context, int)}
+ * protected void observeInstructionCount(Context cx, int instructionCount)
+ * {
+ * MyContext mcx = (MyContext)cx;
+ * long currentTime = System.currentTimeMillis();
+ * if (currentTime - mcx.startTime > 10*1000) {
+ * // More then 10 seconds from Context creation time:
+ * // it is time to stop the script.
+ * // Throw Error instance to ensure that script will never
+ * // get control back through catch or finally.
+ * throw new Error();
+ * }
+ * }
+ *
+ * // Override {@link #doTopCall(Callable,
+ Context, Scriptable,
+ Scriptable, Object[])}
+ * protected Object doTopCall(Callable callable,
+ * Context cx, Scriptable scope,
+ * Scriptable thisObj, Object[] args)
+ * {
+ * MyContext mcx = (MyContext)cx;
+ * mcx.startTime = System.currentTimeMillis();
+ *
+ * return super.doTopCall(callable, cx, scope, thisObj, args);
+ * }
+ *
+ * }
+ *
+ */
+
+public class ContextFactory
+{
+
+ /**
+ * Listener of {@link Context} creation and release events.
+ */
+ public interface Listener
+ {
+ /**
+ * Notify about newly created {@link Context} object.
+ */
+ public void contextCreated(Context cx);
+
+ /**
+ * Notify that the specified {@link Context} instance is no longer
+ * associated with the current thread.
+ */
+ public void contextReleased(Context cx);
+ }
+
+ /**
+ * Get global ContextFactory.
+ *
+ * @see #hasExplicitGlobal()
+ * @see #initGlobal(ContextFactory)
+ */
+ public static ContextFactory getGlobal()
+ {
+ return null;
+ }
+
+ /**
+ * Check if global factory was set.
+ * Return true to indicate that {@link #initGlobal(ContextFactory)} was
+ * already called and false to indicate that the global factory was not
+ * explicitly set.
+ *
+ * @see #getGlobal()
+ * @see #initGlobal(ContextFactory)
+ */
+ public static boolean hasExplicitGlobal()
+ {
+ return false;
+ }
+
+ /**
+ * Set global ContextFactory.
+ * The method can only be called once.
+ *
+ * @see #getGlobal()
+ * @see #hasExplicitGlobal()
+ */
+ public synchronized static void initGlobal(ContextFactory factory)
+ {
+ }
+
+ public interface GlobalSetter {
+ public void setContextFactoryGlobal(ContextFactory factory);
+ public ContextFactory getContextFactoryGlobal();
+ }
+
+ public synchronized static GlobalSetter getGlobalSetter() {
+ return null;
+ }
+
+ /**
+ * Create new {@link Context} instance to be associated with the current
+ * thread.
+ * This is a callback method used by Rhino to create {@link Context}
+ * instance when it is necessary to associate one with the current
+ * execution thread. makeContext() is allowed to call
+ * {@link Context#seal(Object)} on the result to prevent
+ * {@link Context} changes by hostile scripts or applets.
+ */
+ protected Context makeContext()
+ {
+ return null;
+ }
+
+ /**
+ * Implementation of {@link Context#hasFeature(int featureIndex)}.
+ * This can be used to customize {@link Context} without introducing
+ * additional subclasses.
+ */
+ protected boolean hasFeature(Context cx, int featureIndex)
+ {
+ return false;
+ }
+
+ /**
+ * Get ClassLoader to use when searching for Java classes.
+ * Unless it was explicitly initialized with
+ * {@link #initApplicationClassLoader(ClassLoader)} the method returns
+ * null to indicate that Thread.getContextClassLoader() should be used.
+ */
+ public final ClassLoader getApplicationClassLoader()
+ {
+ return null;
+ }
+
+ /**
+ * Set explicit class loader to use when searching for Java classes.
+ *
+ * @see #getApplicationClassLoader()
+ */
+ public final void initApplicationClassLoader(ClassLoader loader)
+ {
+ }
+
+ /**
+ * Checks if this is a sealed ContextFactory.
+ * @see #seal()
+ */
+ public final boolean isSealed()
+ {
+ return false;
+ }
+
+ /**
+ * Seal this ContextFactory so any attempt to modify it like to add or
+ * remove its listeners will throw an exception.
+ * @see #isSealed()
+ */
+ public final void seal()
+ {
+ }
+
+ /**
+ * Get a context associated with the current thread, creating one if need
+ * be. The Context stores the execution state of the JavaScript engine, so
+ * it is required that the context be entered before execution may begin.
+ * Once a thread has entered a Context, then getCurrentContext() may be
+ * called to find the context that is associated with the current thread.
+ *
+ * Calling enterContext() will return either the Context
+ * currently associated with the thread, or will create a new context and
+ * associate it with the current thread. Each call to
+ * enterContext() must have a matching call to
+ * {@link Context#exit()}.
+ *
+ * Context cx = contextFactory.enterContext();
+ * try {
+ * ...
+ * cx.evaluateString(...);
+ * } finally {
+ * Context.exit();
+ * }
+ *
+ * Instead of using enterContext(), exit() pair consider
+ * using {@link #call(ContextAction)} which guarantees proper association
+ * of Context instances with the current thread.
+ * With this method the above example becomes:
+ *
+ * ContextFactory.call(new ContextAction() {
+ * public Object run(Context cx) {
+ * ...
+ * cx.evaluateString(...);
+ * return null;
+ * }
+ * });
+ *
+ * @return a Context associated with the current thread
+ * @see Context#getCurrentContext()
+ * @see Context#exit()
+ * @see #call(ContextAction)
+ */
+ public Context enterContext()
+ {
+ return null;
+ }
+
+ /**
+ * @deprecated use {@link #enterContext()} instead
+ * @return a Context associated with the current thread
+ */
+ @Deprecated
+ public final Context enter()
+ {
+ return null;
+ }
+
+ /**
+ * @deprecated Use {@link Context#exit()} instead.
+ */
+ @Deprecated
+ public final void exit()
+ {
+ }
+
+ /**
+ * Get a Context associated with the current thread, using the given
+ * Context if need be.
+ *
+ * The same as enterContext() except that cx
+ * is associated with the current thread and returned if the current thread
+ * has no associated context and cx is not associated with any
+ * other thread.
+ * @param cx a Context to associate with the thread if possible
+ * @return a Context associated with the current thread
+ * @see #enterContext()
+ * @see #call(ContextAction)
+ * @throws IllegalStateException if cx is already associated
+ * with a different thread
+ */
+ public final Context enterContext(Context cx)
+ {
+ return null;
+ }
+}
diff --git a/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/DefiningClassLoader.java b/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/DefiningClassLoader.java
new file mode 100644
index 00000000000..3819798c351
--- /dev/null
+++ b/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/DefiningClassLoader.java
@@ -0,0 +1,36 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+ package org.mozilla.javascript;
+
+ /**
+ * Load generated classes.
+ *
+ * @author Norris Boyd
+ */
+ public class DefiningClassLoader extends ClassLoader
+ implements GeneratedClassLoader
+ {
+ public DefiningClassLoader() {
+ }
+
+ public DefiningClassLoader(ClassLoader parentLoader) {
+ }
+
+ @Override
+ public Class> defineClass(String name, byte[] data) {
+ return null;
+ }
+
+ @Override
+ public void linkClass(Class> cl) {
+ }
+
+ @Override
+ public Class> loadClass(String name, boolean resolve)
+ throws ClassNotFoundException
+ {
+ return null;
+ }
+ }
\ No newline at end of file
diff --git a/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/Function.java b/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/Function.java
new file mode 100644
index 00000000000..a35a7c2dfba
--- /dev/null
+++ b/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/Function.java
@@ -0,0 +1,46 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// API class
+
+package org.mozilla.javascript;
+
+/**
+ * This is interface that all functions in JavaScript must implement. The interface provides for
+ * calling functions and constructors.
+ *
+ * @see org.mozilla.javascript.Scriptable
+ * @author Norris Boyd
+ */
+public interface Function extends Scriptable {
+ /**
+ * Call the function.
+ *
+ *
Note that the array of arguments is not guaranteed to have length greater than 0.
+ *
+ * @param cx the current Context for this thread
+ * @param scope the scope to execute the function relative to. This is set to the value returned
+ * by getParentScope() except when the function is called from a closure.
+ * @param thisObj the JavaScript this object
+ * @param args the array of arguments
+ * @return the result of the call
+ */
+ Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args);
+
+ /**
+ * Call the function as a constructor.
+ *
+ *
This method is invoked by the runtime in order to satisfy a use of the JavaScript
+ * new operator. This method is expected to create a new object and return it.
+ *
+ * @param cx the current Context for this thread
+ * @param scope an enclosing scope of the caller except when the function is called from a
+ * closure.
+ * @param args the array of arguments
+ * @return the allocated object
+ */
+ Scriptable construct(Context cx, Scriptable scope, Object[] args);
+}
\ No newline at end of file
diff --git a/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/GeneratedClassLoader.java b/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/GeneratedClassLoader.java
new file mode 100644
index 00000000000..c7450862917
--- /dev/null
+++ b/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/GeneratedClassLoader.java
@@ -0,0 +1,34 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// API class
+
+package org.mozilla.javascript;
+
+/**
+ * Interface to define classes from generated byte code.
+ */
+public interface GeneratedClassLoader {
+
+ /**
+ * Define a new Java class.
+ * Classes created via this method should have the same class loader.
+ *
+ * @param name fully qualified class name
+ * @param data class byte code
+ * @return new class object
+ */
+ public Class> defineClass(String name, byte[] data);
+
+ /**
+ * Link the given class.
+ *
+ * @param cl Class instance returned from the previous call to
+ * {@link #defineClass(String, byte[])}
+ * @see java.lang.ClassLoader
+ */
+ public void linkClass(Class> cl);
+}
diff --git a/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/RhinoException.java b/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/RhinoException.java
new file mode 100644
index 00000000000..b11befb4a63
--- /dev/null
+++ b/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/RhinoException.java
@@ -0,0 +1,15 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+package org.mozilla.javascript;
+
+/**
+ * The class of exceptions thrown by the JavaScript engine.
+ */
+public abstract class RhinoException extends RuntimeException
+{
+}
diff --git a/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/Script.java b/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/Script.java
new file mode 100644
index 00000000000..824dc0241c1
--- /dev/null
+++ b/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/Script.java
@@ -0,0 +1,41 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// API class
+
+package org.mozilla.javascript;
+
+/**
+ * All compiled scripts implement this interface.
+ *
+ * This class encapsulates script execution relative to an
+ * object scope.
+ * @since 1.3
+ * @author Norris Boyd
+ */
+
+public interface Script {
+
+ /**
+ * Execute the script.
+ *
+ * The script is executed in a particular runtime Context, which
+ * must be associated with the current thread.
+ * The script is executed relative to a scope--definitions and
+ * uses of global top-level variables and functions will access
+ * properties of the scope object. For compliant ECMA
+ * programs, the scope must be an object that has been initialized
+ * as a global object using Context.initStandardObjects.
+ *
+ *
+ * @param cx the Context associated with the current thread
+ * @param scope the scope to execute relative to
+ * @return the result of executing the script
+ * @see org.mozilla.javascript.Context#initStandardObjects()
+ */
+ public Object exec(Context cx, Scriptable scope);
+
+}
\ No newline at end of file
diff --git a/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/Scriptable.java b/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/Scriptable.java
new file mode 100644
index 00000000000..34616f7ad74
--- /dev/null
+++ b/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/Scriptable.java
@@ -0,0 +1,304 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// API class
+
+package org.mozilla.javascript;
+
+/**
+ * This is interface that all objects in JavaScript must implement.
+ * The interface provides for the management of properties and for
+ * performing conversions.
+ *
+ * Host system implementors may find it easier to extend the ScriptableObject
+ * class rather than implementing Scriptable when writing host objects.
+ *
+ * There are many static methods defined in ScriptableObject that perform
+ * the multiple calls to the Scriptable interface needed in order to
+ * manipulate properties in prototype chains.
+ *
+ *
+ * @see org.mozilla.javascript.ScriptableObject
+ * @author Norris Boyd
+ * @author Nick Thompson
+ * @author Brendan Eich
+ */
+
+public interface Scriptable {
+
+ /**
+ * Get the name of the set of objects implemented by this Java class.
+ * This corresponds to the [[Class]] operation in ECMA and is used
+ * by Object.prototype.toString() in ECMA.
+ * See ECMA 8.6.2 and 15.2.4.2.
+ */
+ public String getClassName();
+
+ /**
+ * Get a named property from the object.
+ *
+ * Looks property up in this object and returns the associated value
+ * if found. Returns NOT_FOUND if not found.
+ * Note that this method is not expected to traverse the prototype
+ * chain. This is different from the ECMA [[Get]] operation.
+ *
+ * Depending on the property selector, the runtime will call
+ * this method or the form of get that takes an
+ * integer:
+ *
+ * JavaScript code Java code
+ * a.b a.get("b", a)
+ * a["foo"] a.get("foo", a)
+ * a[3] a.get(3, a)
+ * a["3"] a.get(3, a)
+ * a[3.0] a.get(3, a)
+ * a["3.0"] a.get("3.0", a)
+ * a[1.1] a.get("1.1", a)
+ * a[-4] a.get(-4, a)
+ *
+ *
+ * The values that may be returned are limited to the following:
+ *
+ * - java.lang.Boolean objects
+ * - java.lang.String objects
+ * - java.lang.Number objects
+ * - org.mozilla.javascript.Scriptable objects
+ * - null
+ * - The value returned by Context.getUndefinedValue()
+ * - NOT_FOUND
+ *
+ * @param name the name of the property
+ * @param start the object in which the lookup began
+ * @return the value of the property (may be null), or NOT_FOUND
+ * @see org.mozilla.javascript.Context#getUndefinedValue
+ */
+ public Object get(String name, Scriptable start);
+
+ /**
+ * Get a property from the object selected by an integral index.
+ *
+ * Identical to get(String, Scriptable) except that
+ * an integral index is used to select the property.
+ *
+ * @param index the numeric index for the property
+ * @param start the object in which the lookup began
+ * @return the value of the property (may be null), or NOT_FOUND
+ * @see org.mozilla.javascript.Scriptable#get(String,Scriptable)
+ */
+ public Object get(int index, Scriptable start);
+
+ /**
+ * Indicates whether or not a named property is defined in an object.
+ *
+ * Does not traverse the prototype chain.
+ *
+ * The property is specified by a String name
+ * as defined for the get method.
+ *
+ * @param name the name of the property
+ * @param start the object in which the lookup began
+ * @return true if and only if the named property is found in the object
+ * @see org.mozilla.javascript.Scriptable#get(String, Scriptable)
+ * @see org.mozilla.javascript.ScriptableObject#getProperty(Scriptable, String)
+ */
+ public boolean has(String name, Scriptable start);
+
+ /**
+ * Indicates whether or not an indexed property is defined in an object.
+ *
+ * Does not traverse the prototype chain.
+ *
+ * The property is specified by an integral index
+ * as defined for the get method.
+ *
+ * @param index the numeric index for the property
+ * @param start the object in which the lookup began
+ * @return true if and only if the indexed property is found in the object
+ * @see org.mozilla.javascript.Scriptable#get(int, Scriptable)
+ * @see org.mozilla.javascript.ScriptableObject#getProperty(Scriptable, int)
+ */
+ public boolean has(int index, Scriptable start);
+
+ /**
+ * Sets a named property in this object.
+ *
+ * The property is specified by a string name
+ * as defined for get.
+ *
+ * The possible values that may be passed in are as defined for
+ * get. A class that implements this method may choose
+ * to ignore calls to set certain properties, in which case those
+ * properties are effectively read-only.
+ * For properties defined in a prototype chain,
+ * use putProperty in ScriptableObject.
+ * Note that if a property a is defined in the prototype p
+ * of an object o, then evaluating o.a = 23 will cause
+ * set to be called on the prototype p with
+ * o as the start parameter.
+ * To preserve JavaScript semantics, it is the Scriptable
+ * object's responsibility to modify o.
+ * This design allows properties to be defined in prototypes and implemented
+ * in terms of getters and setters of Java values without consuming slots
+ * in each instance.
+ *
+ * The values that may be set are limited to the following:
+ *
+ * - java.lang.Boolean objects
+ * - java.lang.String objects
+ * - java.lang.Number objects
+ * - org.mozilla.javascript.Scriptable objects
+ * - null
+ * - The value returned by Context.getUndefinedValue()
+ *
+ * Arbitrary Java objects may be wrapped in a Scriptable by first calling
+ * Context.toObject. This allows the property of a JavaScript
+ * object to contain an arbitrary Java object as a value.
+ * Note that has will be called by the runtime first before
+ * set is called to determine in which object the
+ * property is defined.
+ * Note that this method is not expected to traverse the prototype chain,
+ * which is different from the ECMA [[Put]] operation.
+ * @param name the name of the property
+ * @param start the object whose property is being set
+ * @param value value to set the property to
+ * @see org.mozilla.javascript.Scriptable#has(String, Scriptable)
+ * @see org.mozilla.javascript.Scriptable#get(String, Scriptable)
+ * @see org.mozilla.javascript.ScriptableObject#putProperty(Scriptable, String, Object)
+ * @see org.mozilla.javascript.Context#toObject(Object, Scriptable)
+ */
+ public void put(String name, Scriptable start, Object value);
+
+ /**
+ * Sets an indexed property in this object.
+ *
+ * The property is specified by an integral index
+ * as defined for get.
+ *
+ * Identical to put(String, Scriptable, Object) except that
+ * an integral index is used to select the property.
+ *
+ * @param index the numeric index for the property
+ * @param start the object whose property is being set
+ * @param value value to set the property to
+ * @see org.mozilla.javascript.Scriptable#has(int, Scriptable)
+ * @see org.mozilla.javascript.Scriptable#get(int, Scriptable)
+ * @see org.mozilla.javascript.ScriptableObject#putProperty(Scriptable, int, Object)
+ * @see org.mozilla.javascript.Context#toObject(Object, Scriptable)
+ */
+ public void put(int index, Scriptable start, Object value);
+
+ /**
+ * Removes a property from this object.
+ * This operation corresponds to the ECMA [[Delete]] except that
+ * the no result is returned. The runtime will guarantee that this
+ * method is called only if the property exists. After this method
+ * is called, the runtime will call Scriptable.has to see if the
+ * property has been removed in order to determine the boolean
+ * result of the delete operator as defined by ECMA 11.4.1.
+ *
+ * A property can be made permanent by ignoring calls to remove
+ * it.
+ * The property is specified by a String name
+ * as defined for get.
+ *
+ * To delete properties defined in a prototype chain,
+ * see deleteProperty in ScriptableObject.
+ * @param name the identifier for the property
+ * @see org.mozilla.javascript.Scriptable#get(String, Scriptable)
+ * @see org.mozilla.javascript.ScriptableObject#deleteProperty(Scriptable, String)
+ */
+ public void delete(String name);
+
+ /**
+ * Removes a property from this object.
+ *
+ * The property is specified by an integral index
+ * as defined for get.
+ *
+ * To delete properties defined in a prototype chain,
+ * see deleteProperty in ScriptableObject.
+ *
+ * Identical to delete(String) except that
+ * an integral index is used to select the property.
+ *
+ * @param index the numeric index for the property
+ * @see org.mozilla.javascript.Scriptable#get(int, Scriptable)
+ * @see org.mozilla.javascript.ScriptableObject#deleteProperty(Scriptable, int)
+ */
+ public void delete(int index);
+
+ /**
+ * Get the prototype of the object.
+ * @return the prototype
+ */
+ public Scriptable getPrototype();
+
+ /**
+ * Set the prototype of the object.
+ * @param prototype the prototype to set
+ */
+ public void setPrototype(Scriptable prototype);
+
+ /**
+ * Get the parent scope of the object.
+ * @return the parent scope
+ */
+ public Scriptable getParentScope();
+
+ /**
+ * Set the parent scope of the object.
+ * @param parent the parent scope to set
+ */
+ public void setParentScope(Scriptable parent);
+
+ /**
+ * Get an array of property ids.
+ *
+ * Not all property ids need be returned. Those properties
+ * whose ids are not returned are considered non-enumerable.
+ *
+ * @return an array of Objects. Each entry in the array is either
+ * a java.lang.String or a java.lang.Number
+ */
+ public Object[] getIds();
+
+ /**
+ * Get the default value of the object with a given hint.
+ * The hints are String.class for type String, Number.class for type
+ * Number, Scriptable.class for type Object, and Boolean.class for
+ * type Boolean.
+ *
+ * A hint of null means "no hint".
+ *
+ * See ECMA 8.6.2.6.
+ *
+ * @param hint the type hint
+ * @return the default value
+ */
+ public Object getDefaultValue(Class> hint);
+
+ /**
+ * The instanceof operator.
+ *
+ *
+ * The JavaScript code "lhs instanceof rhs" causes rhs.hasInstance(lhs) to
+ * be called.
+ *
+ *
+ * The return value is implementation dependent so that embedded host objects can
+ * return an appropriate value. See the JS 1.3 language documentation for more
+ * detail.
+ *
+ *
This operator corresponds to the proposed EMCA [[HasInstance]] operator.
+ *
+ * @param instance The value that appeared on the LHS of the instanceof
+ * operator
+ *
+ * @return an implementation dependent value
+ */
+ public boolean hasInstance(Scriptable instance);
+}
+
diff --git a/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/ScriptableObject.java b/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/ScriptableObject.java
new file mode 100644
index 00000000000..298c4fc7fb0
--- /dev/null
+++ b/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/ScriptableObject.java
@@ -0,0 +1,27 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// API class
+
+package org.mozilla.javascript;
+
+/**
+ * This is the default implementation of the Scriptable interface. This
+ * class provides convenient default behavior that makes it easier to
+ * define host objects.
+ *
+ * Various properties and methods of JavaScript objects can be conveniently
+ * defined using methods of ScriptableObject.
+ *
+ * Classes extending ScriptableObject must define the getClassName method.
+ *
+ * @see org.mozilla.javascript.Scriptable
+ * @author Norris Boyd
+ */
+
+public abstract class ScriptableObject implements Scriptable
+{
+}
diff --git a/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/optimizer/ClassCompiler.java b/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/optimizer/ClassCompiler.java
new file mode 100644
index 00000000000..cb2332d3f61
--- /dev/null
+++ b/java/ql/test/experimental/stubs/rhino-1.7.13/org/mozilla/javascript/optimizer/ClassCompiler.java
@@ -0,0 +1,112 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+ package org.mozilla.javascript.optimizer;
+
+ import org.mozilla.javascript.CompilerEnvirons;
+
+ /**
+ * Generates class files from script sources.
+ *
+ * since 1.5 Release 5
+ * @author Igor Bukanov
+ */
+
+ public class ClassCompiler
+ {
+ /**
+ * Construct ClassCompiler that uses the specified compiler environment
+ * when generating classes.
+ */
+ public ClassCompiler(CompilerEnvirons compilerEnv)
+ {
+ }
+
+ /**
+ * Set the class name to use for main method implementation.
+ * The class must have a method matching
+ * public static void main(Script sc, String[] args), it will be
+ * called when main(String[] args) is called in the generated
+ * class. The class name should be fully qulified name and include the
+ * package name like in org.foo.Bar.
+ */
+ public void setMainMethodClass(String className)
+ {
+ }
+
+ /**
+ * Get the name of the class for main method implementation.
+ * @see #setMainMethodClass(String)
+ */
+ public String getMainMethodClass()
+ {
+ return null;
+ }
+
+ /**
+ * Get the compiler environment the compiler uses.
+ */
+ public CompilerEnvirons getCompilerEnv()
+ {
+ return null;
+ }
+
+ /**
+ * Get the class that the generated target will extend.
+ */
+ public Class> getTargetExtends()
+ {
+ return null;
+ }
+
+ /**
+ * Set the class that the generated target will extend.
+ *
+ * @param extendsClass the class it extends
+ */
+ public void setTargetExtends(Class> extendsClass)
+ {
+ }
+
+ /**
+ * Get the interfaces that the generated target will implement.
+ */
+ public Class>[] getTargetImplements()
+ {
+ return null;
+ }
+
+ /**
+ * Set the interfaces that the generated target will implement.
+ *
+ * @param implementsClasses an array of Class objects, one for each
+ * interface the target will extend
+ */
+ public void setTargetImplements(Class>[] implementsClasses)
+ {
+ }
+
+ /**
+ * Compile JavaScript source into one or more Java class files.
+ * The first compiled class will have name mainClassName.
+ * If the results of {@link #getTargetExtends()} or
+ * {@link #getTargetImplements()} are not null, then the first compiled
+ * class will extend the specified super class and implement
+ * specified interfaces.
+ *
+ * @return array where elements with even indexes specifies class name
+ * and the following odd index gives class file body as byte[]
+ * array. The initial element of the array always holds
+ * mainClassName and array[1] holds its byte code.
+ */
+ public Object[] compileToClassFiles(String source,
+ String sourceLocation,
+ int lineno,
+ String mainClassName)
+ {
+ return null;
+ }
+ }
\ No newline at end of file
diff --git a/java/ql/test/library-tests/dataflow/taint-jackson/Test.java b/java/ql/test/library-tests/dataflow/taint-jackson/Test.java
index 2caf9e4ee80..3be85336e26 100644
--- a/java/ql/test/library-tests/dataflow/taint-jackson/Test.java
+++ b/java/ql/test/library-tests/dataflow/taint-jackson/Test.java
@@ -3,33 +3,53 @@ import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.StringWriter;
import java.io.Writer;
+import java.util.Iterator;
+import java.util.HashMap;
+import java.util.Map;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
+import com.fasterxml.jackson.databind.ObjectReader;
class Test {
+ public static class Potato {
+ private String name;
+
+ private String getName() {
+ return name;
+ }
+ }
+
public static String taint() {
return "tainted";
}
+ public static void sink(Object any) {}
+
public static void jacksonObjectMapper() throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException {
String s = taint();
ObjectMapper om = new ObjectMapper();
File file = new File("testFile");
om.writeValue(file, s);
+ sink(file); //$hasTaintFlow
OutputStream out = new FileOutputStream(file);
om.writeValue(out, s);
+ sink(file); //$hasTaintFlow
Writer writer = new StringWriter();
om.writeValue(writer, s);
+ sink(writer); //$hasTaintFlow
JsonGenerator generator = new JsonFactory().createGenerator(new StringWriter());
om.writeValue(generator, s);
+ sink(generator); //$hasTaintFlow
String t = om.writeValueAsString(s);
- System.out.println(t);
+ sink(t); //$hasTaintFlow
byte[] bs = om.writeValueAsBytes(s);
String reconstructed = new String(bs, "utf-8");
- System.out.println(reconstructed);
+ sink(bs); //$hasTaintFlow
+ sink(reconstructed); //$hasTaintFlow
}
public static void jacksonObjectWriter() throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException {
@@ -37,16 +57,56 @@ class Test {
ObjectWriter ow = new ObjectWriter();
File file = new File("testFile");
ow.writeValue(file, s);
+ sink(file); //$hasTaintFlow
OutputStream out = new FileOutputStream(file);
ow.writeValue(out, s);
+ sink(out); //$hasTaintFlow
Writer writer = new StringWriter();
ow.writeValue(writer, s);
+ sink(writer); //$hasTaintFlow
JsonGenerator generator = new JsonFactory().createGenerator(new StringWriter());
ow.writeValue(generator, s);
+ sink(generator); //$hasTaintFlow
String t = ow.writeValueAsString(s);
- System.out.println(t);
+ sink(t); //$hasTaintFlow
byte[] bs = ow.writeValueAsBytes(s);
String reconstructed = new String(bs, "utf-8");
- System.out.println(reconstructed);
+ sink(bs); //$hasTaintFlow
+ sink(reconstructed); //$hasTaintFlow
+ }
+
+ public static void jacksonObjectReader() throws java.io.IOException {
+ String s = taint();
+ ObjectMapper om = new ObjectMapper();
+ ObjectReader reader = om.readerFor(Potato.class);
+ sink(reader.readValue(s)); //$hasTaintFlow
+ sink(reader.readValue(s, Potato.class).name); //$hasTaintFlow
+ sink(reader.readValue(s, Potato.class).getName()); //$hasTaintFlow
+ }
+
+ public static void jacksonObjectReaderIterable() throws java.io.IOException {
+ String s = taint();
+ ObjectMapper om = new ObjectMapper();
+ ObjectReader reader = om.readerFor(Potato.class);
+ sink(reader.readValues(s)); //$hasTaintFlow
+ Iterator pIterator = reader.readValues(s, Potato.class);
+ while(pIterator.hasNext()) {
+ Potato p = pIterator.next();
+ sink(p); //$hasTaintFlow
+ sink(p.name); //$hasTaintFlow
+ sink(p.getName()); //$hasTaintFlow
+ }
+ }
+
+ public static void jacksonTwoStepDeserialization() throws java.io.IOException {
+ String s = taint();
+ Map taintedParams = new HashMap<>();
+ taintedParams.put("name", s);
+ ObjectMapper om = new ObjectMapper();
+ JsonNode jn = om.valueToTree(taintedParams);
+ sink(jn); //$hasTaintFlow
+ Potato p = om.convertValue(jn, Potato.class);
+ sink(p); //$hasTaintFlow
+ sink(p.getName()); //$hasTaintFlow
}
}
diff --git a/java/ql/test/library-tests/dataflow/taint-jackson/dataFlow.expected b/java/ql/test/library-tests/dataflow/taint-jackson/dataFlow.expected
index 122b21d50fe..e69de29bb2d 100644
--- a/java/ql/test/library-tests/dataflow/taint-jackson/dataFlow.expected
+++ b/java/ql/test/library-tests/dataflow/taint-jackson/dataFlow.expected
@@ -1,48 +0,0 @@
-| ../../../stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectMapper.java:10:43:10:54 | value |
-| ../../../stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectMapper.java:13:73:13:84 | value |
-| ../../../stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectMapper.java:16:44:16:55 | value |
-| ../../../stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectMapper.java:19:36:19:47 | value |
-| ../../../stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectMapper.java:22:35:22:46 | value |
-| ../../../stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectMapper.java:26:36:26:47 | value |
-| ../../../stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectWriter.java:10:43:10:54 | value |
-| ../../../stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectWriter.java:13:73:13:84 | value |
-| ../../../stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectWriter.java:16:44:16:55 | value |
-| ../../../stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectWriter.java:19:36:19:47 | value |
-| ../../../stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectWriter.java:22:35:22:46 | value |
-| ../../../stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectWriter.java:26:36:26:47 | value |
-| Test.java:18:14:18:20 | taint(...) |
-| Test.java:21:17:21:20 | file [post update] |
-| Test.java:21:23:21:23 | s |
-| Test.java:22:43:22:46 | file |
-| Test.java:23:17:23:19 | out [post update] |
-| Test.java:23:22:23:22 | s |
-| Test.java:25:17:25:22 | writer [post update] |
-| Test.java:25:25:25:25 | s |
-| Test.java:27:17:27:25 | generator [post update] |
-| Test.java:27:28:27:28 | s |
-| Test.java:28:14:28:37 | writeValueAsString(...) |
-| Test.java:28:36:28:36 | s |
-| Test.java:29:22:29:22 | t |
-| Test.java:30:15:30:37 | writeValueAsBytes(...) |
-| Test.java:30:36:30:36 | s |
-| Test.java:31:26:31:48 | new String(...) |
-| Test.java:31:37:31:38 | bs |
-| Test.java:32:22:32:34 | reconstructed |
-| Test.java:36:14:36:20 | taint(...) |
-| Test.java:39:17:39:20 | file [post update] |
-| Test.java:39:23:39:23 | s |
-| Test.java:40:43:40:46 | file |
-| Test.java:41:17:41:19 | out [post update] |
-| Test.java:41:22:41:22 | s |
-| Test.java:43:17:43:22 | writer [post update] |
-| Test.java:43:25:43:25 | s |
-| Test.java:45:17:45:25 | generator [post update] |
-| Test.java:45:28:45:28 | s |
-| Test.java:46:14:46:37 | writeValueAsString(...) |
-| Test.java:46:36:46:36 | s |
-| Test.java:47:22:47:22 | t |
-| Test.java:48:15:48:37 | writeValueAsBytes(...) |
-| Test.java:48:36:48:36 | s |
-| Test.java:49:26:49:48 | new String(...) |
-| Test.java:49:37:49:38 | bs |
-| Test.java:50:22:50:34 | reconstructed |
diff --git a/java/ql/test/library-tests/dataflow/taint-jackson/dataFlow.ql b/java/ql/test/library-tests/dataflow/taint-jackson/dataFlow.ql
index 333cf485f07..0836906530b 100644
--- a/java/ql/test/library-tests/dataflow/taint-jackson/dataFlow.ql
+++ b/java/ql/test/library-tests/dataflow/taint-jackson/dataFlow.ql
@@ -1,17 +1,34 @@
+import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.dataflow.FlowSources
+import TestUtilities.InlineExpectationsTest
class Conf extends TaintTracking::Configuration {
Conf() { this = "qltest:dataflow:jackson" }
- override predicate isSource(DataFlow::Node source) {
- source.asExpr().(MethodAccess).getMethod().hasName("taint")
+ override predicate isSource(DataFlow::Node n) {
+ n.asExpr().(MethodAccess).getMethod().hasName("taint")
+ or
+ n instanceof RemoteFlowSource
}
- override predicate isSink(DataFlow::Node sink) { any() }
+ override predicate isSink(DataFlow::Node n) {
+ exists(MethodAccess ma | ma.getMethod().hasName("sink") | n.asExpr() = ma.getAnArgument())
+ }
}
-from DataFlow::Node source, DataFlow::Node sink, Conf config
-where config.hasFlow(source, sink)
-select sink
+class HasFlowTest extends InlineExpectationsTest {
+ HasFlowTest() { this = "HasFlowTest" }
+
+ override string getARelevantTag() { result = "hasTaintFlow" }
+
+ override predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "hasTaintFlow" and
+ exists(DataFlow::Node src, DataFlow::Node sink, Conf conf | conf.hasFlow(src, sink) |
+ sink.getLocation() = location and
+ element = sink.toString() and
+ value = ""
+ )
+ }
+}
diff --git a/java/ql/test/query-tests/security/CWE-502/KryoTest.java b/java/ql/test/query-tests/security/CWE-502/KryoTest.java
new file mode 100644
index 00000000000..8890bad91b9
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-502/KryoTest.java
@@ -0,0 +1,34 @@
+
+import java.io.*;
+import java.net.Socket;
+import com.esotericsoftware.kryo.Kryo;
+import com.esotericsoftware.kryo.pool.KryoPool;
+import com.esotericsoftware.kryo.io.Input;
+
+public class KryoTest {
+
+ private Kryo getSafeKryo() {
+ Kryo kryo = new Kryo();
+ kryo.setRegistrationRequired(true);
+ // ... kryo.register(A.class) ...
+ return kryo;
+ }
+
+ public void kryoDeserialize(Socket sock) throws java.io.IOException {
+ KryoPool kryoPool = new KryoPool.Builder(this::getSafeKryo).softReferences().build();
+ Input input = new Input(sock.getInputStream());
+ Object o = kryoPool.run(kryo -> kryo.readClassAndObject(input)); // OK
+ }
+
+ public void kryoDeserialize2(Socket sock) throws java.io.IOException {
+ KryoPool kryoPool = new KryoPool.Builder(this::getSafeKryo).softReferences().build();
+ Input input = new Input(sock.getInputStream());
+ Kryo k = kryoPool.borrow();
+ try {
+ Object o = k.readClassAndObject(input); // OK
+ } finally {
+ kryoPool.release(k);
+ }
+ }
+
+}
diff --git a/java/ql/test/stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/JsonNode.java b/java/ql/test/stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/JsonNode.java
index a26eb2592c6..b04572cd4da 100644
--- a/java/ql/test/stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/JsonNode.java
+++ b/java/ql/test/stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/JsonNode.java
@@ -1,6 +1,8 @@
package com.fasterxml.jackson.databind;
-public class JsonNode {
+import java.util.*;
+
+public abstract class JsonNode implements Iterable {
public JsonNode() {
}
-}
\ No newline at end of file
+}
diff --git a/java/ql/test/stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/MappingIterator.java b/java/ql/test/stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/MappingIterator.java
new file mode 100644
index 00000000000..ac427ef01c9
--- /dev/null
+++ b/java/ql/test/stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/MappingIterator.java
@@ -0,0 +1,28 @@
+package com.fasterxml.jackson.databind;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.*;
+
+public class MappingIterator implements Iterator, Closeable {
+
+ @Override
+ public boolean hasNext() {
+ return false;
+ }
+
+ @Override
+ public T next() {
+ return null;
+ }
+
+ @Override
+ public void remove() {
+
+ }
+
+ @Override
+ public void close() throws IOException {
+
+ }
+}
diff --git a/java/ql/test/stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectMapper.java b/java/ql/test/stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectMapper.java
index 455e0c0d309..71dc99a351d 100644
--- a/java/ql/test/stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectMapper.java
+++ b/java/ql/test/stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectMapper.java
@@ -26,4 +26,16 @@ public class ObjectMapper {
public String writeValueAsString(Object value) {
return null;
}
+
+ public ObjectReader readerFor(Class> type) {
+ return null;
+ }
+
+ public T valueToTree(Object fromValue) throws IllegalArgumentException {
+ return null;
+ }
+
+ public T convertValue(Object fromValue, Class toValueType) throws IllegalArgumentException {
+ return null;
+ }
}
diff --git a/java/ql/test/stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectReader.java b/java/ql/test/stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectReader.java
new file mode 100644
index 00000000000..f067a3e95a4
--- /dev/null
+++ b/java/ql/test/stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectReader.java
@@ -0,0 +1,82 @@
+package com.fasterxml.jackson.databind;
+
+import java.io.*;
+
+public class ObjectReader {
+ public ObjectReader forType(Class> valueType) {
+ return null;
+ }
+
+ public T readValue(String src) {
+ return null;
+ }
+
+ public T readValue(String src, Class valueType) throws IOException {
+ return null;
+ }
+
+ public T readValue(byte[] content) throws IOException {
+ return null;
+ }
+
+ public T readValue(byte[] content, Class valueType) throws IOException {
+ return null;
+ }
+
+ public T readValue(File src) throws IOException {
+ return null;
+ }
+
+ public T readValue(InputStream src) throws IOException {
+ return null;
+ }
+
+ public T readValue(InputStream src, Class valueType) throws IOException {
+ return null;
+ }
+
+ public T readValue(Reader src) throws IOException {
+ return null;
+ }
+
+ public T readValue(Reader src, Class valueType) throws IOException {
+ return null;
+ }
+
+ public MappingIterator readValues(String src) {
+ return null;
+ }
+
+ public MappingIterator readValues(String src, Class valueType) throws IOException {
+ return null;
+ }
+
+ public MappingIterator readValues(byte[] content) throws IOException {
+ return null;
+ }
+
+ public MappingIterator readValues(byte[] content, Class valueType) throws IOException {
+ return null;
+ }
+
+ public MappingIterator readValues(File src) throws IOException {
+ return null;
+ }
+
+ public MappingIterator readValues(InputStream src) throws IOException {
+ return null;
+ }
+
+ public MappingIterator readValues(InputStream src, Class valueType) throws IOException {
+ return null;
+ }
+
+ public MappingIterator readValues(Reader src) throws IOException {
+ return null;
+ }
+
+ public MappingIterator readValues(Reader src, Class valueType) throws IOException {
+ return null;
+ }
+
+}
diff --git a/java/ql/test/stubs/jython-2.7.2/org/python/antlr/base/mod.java b/java/ql/test/stubs/jython-2.7.2/org/python/antlr/base/mod.java
new file mode 100644
index 00000000000..785212f62fa
--- /dev/null
+++ b/java/ql/test/stubs/jython-2.7.2/org/python/antlr/base/mod.java
@@ -0,0 +1,5 @@
+// Autogenerated AST node
+package org.python.antlr.base;
+
+public abstract class mod {
+}
diff --git a/java/ql/test/stubs/jython-2.7.2/org/python/core/BytecodeLoader.java b/java/ql/test/stubs/jython-2.7.2/org/python/core/BytecodeLoader.java
new file mode 100644
index 00000000000..e414216ed03
--- /dev/null
+++ b/java/ql/test/stubs/jython-2.7.2/org/python/core/BytecodeLoader.java
@@ -0,0 +1,47 @@
+// Copyright (c) Corporation for National Research Initiatives
+package org.python.core;
+
+import java.util.List;
+
+/**
+ * Utility class for loading compiled Python modules and Java classes defined in Python modules.
+ */
+public class BytecodeLoader {
+
+ /**
+ * Turn the Java class file data into a Java class.
+ *
+ * @param name fully-qualified binary name of the class
+ * @param data a class file as a byte array
+ * @param referents super-classes and interfaces that the new class will reference.
+ */
+ @SuppressWarnings("unchecked")
+ public static Class> makeClass(String name, byte[] data, Class>... referents) {
+ return null;
+ }
+
+ /**
+ * Turn the Java class file data into a Java class.
+ *
+ * @param name the name of the class
+ * @param referents super-classes and interfaces that the new class will reference.
+ * @param data a class file as a byte array
+ */
+ public static Class> makeClass(String name, List> referents, byte[] data) {
+ return null;
+ }
+
+ /**
+ * Turn the Java class file data for a compiled Python module into a {@code PyCode} object, by
+ * constructing an instance of the named class and calling the instance's
+ * {@link PyRunnable#getMain()}.
+ *
+ * @param name fully-qualified binary name of the class
+ * @param data a class file as a byte array
+ * @param filename to provide to the constructor of the named class
+ * @return the {@code PyCode} object produced by the named class' {@code getMain}
+ */
+ public static PyCode makeCode(String name, byte[] data, String filename) {
+ return null;
+ }
+}
diff --git a/java/ql/test/stubs/jython-2.7.2/org/python/core/CompileMode.java b/java/ql/test/stubs/jython-2.7.2/org/python/core/CompileMode.java
new file mode 100644
index 00000000000..cf7ad1e7201
--- /dev/null
+++ b/java/ql/test/stubs/jython-2.7.2/org/python/core/CompileMode.java
@@ -0,0 +1,11 @@
+package org.python.core;
+
+public enum CompileMode {
+ eval,
+ single,
+ exec;
+
+ public static CompileMode getMode(String mode) {
+ return null;
+ }
+}
diff --git a/java/ql/test/stubs/jython-2.7.2/org/python/core/CompilerFlags.java b/java/ql/test/stubs/jython-2.7.2/org/python/core/CompilerFlags.java
new file mode 100644
index 00000000000..916b93c84ea
--- /dev/null
+++ b/java/ql/test/stubs/jython-2.7.2/org/python/core/CompilerFlags.java
@@ -0,0 +1,17 @@
+// At some future point this will also be extended - in conjunction with
+// Py#compileFlags - to add
+// support for a compiler factory that user code can choose in place of the
+// normal compiler.
+// (Perhaps a better name might have been "CompilerOptions".)
+
+package org.python.core;
+
+import java.io.Serializable;
+
+public class CompilerFlags implements Serializable {
+ public CompilerFlags() {
+ }
+
+ public CompilerFlags(int co_flags) {
+ }
+}
diff --git a/java/ql/test/stubs/jython-2.7.2/org/python/core/Py.java b/java/ql/test/stubs/jython-2.7.2/org/python/core/Py.java
new file mode 100644
index 00000000000..cc0c9f1e4bd
--- /dev/null
+++ b/java/ql/test/stubs/jython-2.7.2/org/python/core/Py.java
@@ -0,0 +1,134 @@
+// Copyright (c) Corporation for National Research Initiatives
+package org.python.core;
+
+import java.io.InputStream;
+import java.io.Serializable;
+
+import org.python.antlr.base.mod;
+
+public final class Py {
+ /**
+ Convert a given PyObject to an instance of a Java class.
+ Identical to o.__tojava__(c) except that it will
+ raise a TypeError if the conversion fails.
+ @param o the PyObject to convert.
+ @param c the class to convert it to.
+ **/
+ @SuppressWarnings("unchecked")
+ public static T tojava(PyObject o, Class c) {
+ return null;
+ }
+
+ // ??pending: was @deprecated but is actually used by proxie code.
+ // Can get rid of it?
+ public static Object tojava(PyObject o, String s) {
+ return null;
+ }
+
+ /**
+ * Uses the PyObjectAdapter passed to {@link PySystemState#initialize} to turn o into a PyObject.
+ *
+ * @see ClassicPyObjectAdapter - default PyObjectAdapter type
+ */
+ public static PyObject java2py(Object o) {
+ return null;
+ }
+
+ /**
+ * Uses the PyObjectAdapter passed to {@link PySystemState#initialize} to turn
+ * objects into an array of PyObjects.
+ *
+ * @see ClassicPyObjectAdapter - default PyObjectAdapter type
+ */
+ public static PyObject[] javas2pys(Object... objects) {
+ return null;
+ }
+
+ public static PyObject makeClass(String name, PyObject[] bases, PyCode code,
+ PyObject[] closure_cells) {
+ return null;
+ }
+
+ public static PyObject makeClass(String name, PyObject base, PyObject dict) {
+ return null;
+ }
+
+ /**
+ * Create a new Python class.
+ *
+ * @param name the String name of the class
+ * @param bases an array of PyObject base classes
+ * @param dict the class's namespace, containing the class body
+ * definition
+ * @return a new Python Class PyObject
+ */
+ public static PyObject makeClass(String name, PyObject[] bases, PyObject dict) {
+ return null;
+ }
+
+ public static CompilerFlags getCompilerFlags() {
+ return null;
+ }
+
+ public static CompilerFlags getCompilerFlags(int flags, boolean dont_inherit) {
+ return null;
+ }
+
+ public static CompilerFlags getCompilerFlags(CompilerFlags flags, boolean dont_inherit) {
+ return null;
+ }
+
+ // w/o compiler-flags
+ public static PyCode compile(InputStream istream, String filename, CompileMode kind) {
+ return null;
+ }
+
+ /**
+ * Entry point for compiling modules.
+ *
+ * @param node Module node, coming from the parsing process
+ * @param name Internal name for the compiled code. Typically generated by
+ * calling {@link #getName()}.
+ * @param filename Source file name
+ * @param linenumbers True to track source line numbers on the generated
+ * code
+ * @param printResults True to call the sys.displayhook on the result of
+ * the code
+ * @param cflags Compiler flags
+ * @return Code object for the compiled module
+ */
+ public static PyCode compile_flags(mod node, String name, String filename,
+ boolean linenumbers, boolean printResults,
+ CompilerFlags cflags) {
+ return null;
+ }
+
+ public static PyCode compile_flags(mod node, String filename,
+ CompileMode kind, CompilerFlags cflags) {
+ return null;
+ }
+
+ /**
+ * Compiles python source code coming from a file or another external stream
+ */
+ public static PyCode compile_flags(InputStream istream, String filename,
+ CompileMode kind, CompilerFlags cflags) {
+ return null;
+ }
+
+ /**
+ * Compiles python source code coming from String (raw bytes) data.
+ *
+ * If the String is properly decoded (from PyUnicode) the PyCF_SOURCE_IS_UTF8 flag
+ * should be specified.
+ */
+ public static PyCode compile_flags(String data, String filename,
+ CompileMode kind, CompilerFlags cflags) {
+ return null;
+ }
+
+ public static PyObject compile_command_flags(String string, String filename,
+ CompileMode kind, CompilerFlags cflags, boolean stdprompt) {
+ return null;
+ }
+}
diff --git a/java/ql/test/stubs/jython-2.7.2/org/python/core/PyCode.java b/java/ql/test/stubs/jython-2.7.2/org/python/core/PyCode.java
new file mode 100644
index 00000000000..9b7c99f94fa
--- /dev/null
+++ b/java/ql/test/stubs/jython-2.7.2/org/python/core/PyCode.java
@@ -0,0 +1,43 @@
+// Copyright (c) Corporation for National Research Initiatives
+package org.python.core;
+
+/**
+ * A super class for all python code implementations.
+ */
+public abstract class PyCode extends PyObject
+{
+ abstract public PyObject call(ThreadState state,
+ PyObject args[], String keywords[],
+ PyObject globals, PyObject[] defaults,
+ PyObject closure);
+
+ abstract public PyObject call(ThreadState state,
+ PyObject self, PyObject args[],
+ String keywords[],
+ PyObject globals, PyObject[] defaults,
+ PyObject closure);
+
+ abstract public PyObject call(ThreadState state,
+ PyObject globals, PyObject[] defaults,
+ PyObject closure);
+
+ abstract public PyObject call(ThreadState state,
+ PyObject arg1, PyObject globals,
+ PyObject[] defaults, PyObject closure);
+
+ abstract public PyObject call(ThreadState state,
+ PyObject arg1, PyObject arg2,
+ PyObject globals, PyObject[] defaults,
+ PyObject closure);
+
+ abstract public PyObject call(ThreadState state,
+ PyObject arg1, PyObject arg2, PyObject arg3,
+ PyObject globals, PyObject[] defaults,
+ PyObject closure);
+
+ abstract public PyObject call(ThreadState state,
+ PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4,
+ PyObject globals, PyObject[] defaults,
+ PyObject closure);
+
+}
diff --git a/java/ql/test/stubs/jython-2.7.2/org/python/core/PyException.java b/java/ql/test/stubs/jython-2.7.2/org/python/core/PyException.java
new file mode 100644
index 00000000000..3a0a6c52c69
--- /dev/null
+++ b/java/ql/test/stubs/jython-2.7.2/org/python/core/PyException.java
@@ -0,0 +1,12 @@
+// Copyright (c) Corporation for National Research Initiatives
+package org.python.core;
+import java.io.*;
+
+/**
+ * A wrapper for all python exception. Note that the well-known python exceptions are not
+ * subclasses of PyException. Instead the python exception class is stored in the type
+ * field and value or class instance is stored in the value field.
+ */
+public class PyException extends RuntimeException
+{
+}
diff --git a/java/ql/test/stubs/jython-2.7.2/org/python/core/PyObject.java b/java/ql/test/stubs/jython-2.7.2/org/python/core/PyObject.java
new file mode 100644
index 00000000000..00993123461
--- /dev/null
+++ b/java/ql/test/stubs/jython-2.7.2/org/python/core/PyObject.java
@@ -0,0 +1,11 @@
+// Copyright (c) Corporation for National Research Initiatives
+package org.python.core;
+
+import java.io.Serializable;
+
+/**
+ * All objects known to the Jython runtime system are represented by an instance of the class
+ * {@code PyObject} or one of its subclasses.
+ */
+public class PyObject implements Serializable {
+}
diff --git a/java/ql/test/stubs/jython-2.7.2/org/python/core/PySystemState.java b/java/ql/test/stubs/jython-2.7.2/org/python/core/PySystemState.java
new file mode 100644
index 00000000000..8444bbba70e
--- /dev/null
+++ b/java/ql/test/stubs/jython-2.7.2/org/python/core/PySystemState.java
@@ -0,0 +1,177 @@
+// Copyright (c) Corporation for National Research Initiatives
+package org.python.core;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Properties;
+
+/**
+ * The "sys" module.
+ */
+// xxx Many have lamented, this should really be a module!
+// but it will require some refactoring to see this wish come true.
+public class PySystemState extends PyObject {
+ public PySystemState() {
+ }
+
+ public static void classDictInit(PyObject dict) {
+ }
+
+ public ClassLoader getSyspathJavaLoader() {
+ return null;
+ }
+
+ // xxx fix this accessors
+ public PyObject __findattr_ex__(String name) {
+ return null;
+ }
+
+ public void __setattr__(String name, PyObject value) {
+ }
+
+ public void __delattr__(String name) {
+ }
+
+ public PyObject gettrace() {
+ return null;
+ }
+
+ public void settrace(PyObject tracefunc) {
+ }
+
+ /**
+ * Change the current working directory to the specified path.
+ *
+ * path is assumed to be absolute and canonical (via os.path.realpath).
+ *
+ * @param path a path String
+ */
+ public void setCurrentWorkingDir(String path) {
+ }
+
+ /**
+ * Return a string representing the current working directory.
+ *
+ * @return a path String
+ */
+ public String getCurrentWorkingDir() {
+ return null;
+ }
+
+ /**
+ * Resolve a path. Returns the full path taking the current working directory into account.
+ *
+ * @param path a path String
+ * @return a resolved path String
+ */
+ public String getPath(String path) {
+ return null;
+ }
+
+ /**
+ * Resolve a path, returning a {@link File}, taking the current working directory into account.
+ *
+ * @param path a path String
+ * @return a resolved File
+ */
+ public File getFile(String path) {
+ return null;
+ }
+
+ public ClassLoader getClassLoader() {
+ return null;
+ }
+
+ public void setClassLoader(ClassLoader classLoader) {
+ }
+
+ public static Properties getBaseProperties() {
+ return null;
+ }
+
+ public static synchronized void initialize() {
+ }
+
+ public static synchronized void initialize(Properties preProperties,
+ Properties postProperties) {
+ }
+
+ public static synchronized void initialize(Properties preProperties, Properties postProperties,
+ String[] argv) {
+ }
+
+ public static synchronized void initialize(Properties preProperties, Properties postProperties,
+ String[] argv, ClassLoader classLoader) {
+ }
+
+ /**
+ * Add a classpath directory to the list of places that are searched for java packages.
+ *
+ * Note. Classes found in directory and sub-directory are not made available to jython by
+ * this call. It only makes the java package found in the directory available. This call is
+ * mostly useful if jython is embedded in an application that deals with its own class loaders.
+ * A servlet container is a very good example. Calling
+ * {@code add_classdir("/WEB-INF/classes")} makes the java packages in WEB-INF classes
+ * available to jython import. However the actual class loading is completely handled by the
+ * servlet container's context classloader.
+ */
+ public static void add_classdir(String directoryPath) {
+ }
+
+ /**
+ * Add a .jar and .zip directory to the list of places that are searched for java .jar and .zip
+ * files. The .jar and .zip files found will not be cached.
+ *
+ * Note. Classes in .jar and .zip files found in the directory are not made available to
+ * jython by this call. See the note for add_classdir(dir) for more details.
+ *
+ * @param directoryPath The name of a directory.
+ *
+ * @see #add_classdir
+ */
+ public static void add_extdir(String directoryPath) {
+ }
+
+ /**
+ * Add a .jar and .zip directory to the list of places that are searched for java .jar and .zip
+ * files.
+ *
+ * Note. Classes in .jar and .zip files found in the directory are not made available to
+ * jython by this call. See the note for add_classdir(dir) for more details.
+ *
+ * @param directoryPath The name of a directory.
+ * @param cache Controls if the packages in the zip and jar file should be cached.
+ *
+ * @see #add_classdir
+ */
+ public static void add_extdir(String directoryPath, boolean cache) {
+ }
+
+ // Not public by design. We can't rebind the displayhook if
+ // a reflected function is inserted in the class dict.
+
+ /**
+ * Exit a Python program with the given status.
+ *
+ * @param status the value to exit with
+ * @throws PyException {@code SystemExit} always throws this exception. When caught at top level
+ * the program will exit.
+ */
+ public static void exit(PyObject status) {
+ }
+
+ /**
+ * Exit a Python program with the status 0.
+ */
+ public static void exit() {
+ }
+
+ public static void exc_clear() {
+ }
+
+ public void cleanup() {
+ }
+
+ public void close() {
+ }
+}
diff --git a/java/ql/test/stubs/jython-2.7.2/org/python/core/ThreadState.java b/java/ql/test/stubs/jython-2.7.2/org/python/core/ThreadState.java
new file mode 100644
index 00000000000..920270fe053
--- /dev/null
+++ b/java/ql/test/stubs/jython-2.7.2/org/python/core/ThreadState.java
@@ -0,0 +1,28 @@
+// Copyright (c) Corporation for National Research Initiatives
+package org.python.core;
+
+// a ThreadState refers to one PySystemState; this weak ref allows for tracking all ThreadState objects
+// that refer to a given PySystemState
+
+public class ThreadState {
+
+ public PyException exception;
+
+ public ThreadState(PySystemState systemState) {
+ setSystemState(systemState);
+ }
+
+ public void setSystemState(PySystemState systemState) {
+ }
+
+ public PySystemState getSystemState() {
+ return null;
+ }
+
+ public boolean enterRepr(PyObject obj) {
+ return false;
+ }
+
+ public void exitRepr(PyObject obj) {
+ }
+}
diff --git a/java/ql/test/stubs/jython-2.7.2/org/python/util/InteractiveInterpreter.java b/java/ql/test/stubs/jython-2.7.2/org/python/util/InteractiveInterpreter.java
new file mode 100644
index 00000000000..b12fa617227
--- /dev/null
+++ b/java/ql/test/stubs/jython-2.7.2/org/python/util/InteractiveInterpreter.java
@@ -0,0 +1,114 @@
+// Copyright (c) Corporation for National Research Initiatives
+package org.python.util;
+
+import org.python.core.*;
+
+/**
+ * This class provides the interface for compiling and running code that supports an interactive
+ * interpreter.
+ */
+// Based on CPython-1.5.2's code module
+public class InteractiveInterpreter extends PythonInterpreter {
+
+ /**
+ * Construct an InteractiveInterpreter with all default characteristics: default state (from
+ * {@link Py#getSystemState()}), and a new empty dictionary of local variables.
+ * */
+ public InteractiveInterpreter() {
+ }
+
+ /**
+ * Construct an InteractiveInterpreter with state (from {@link Py#getSystemState()}), and the
+ * specified dictionary of local variables.
+ *
+ * @param locals dictionary to use, or if null, a new empty one will be created
+ */
+ public InteractiveInterpreter(PyObject locals) {
+ }
+
+ /**
+ * Construct an InteractiveInterpreter with, and system state the specified dictionary of local
+ * variables.
+ *
+ * @param locals dictionary to use, or if null, a new empty one will be created
+ * @param systemState interpreter state, or if null use {@link Py#getSystemState()}
+ */
+ public InteractiveInterpreter(PyObject locals, PySystemState systemState) {
+ }
+
+ /**
+ * Compile and run some source in the interpreter, in the mode {@link CompileMode#single} which
+ * is used for incremental compilation at the interactive console, known as {@code }.
+ *
+ * @param source Python code
+ * @return true to indicate a partial statement was entered
+ */
+ public boolean runsource(String source) {
+ return false;
+ }
+
+ /**
+ * Compile and run some source in the interpreter, in the mode {@link CompileMode#single} which
+ * is used for incremental compilation at the interactive console.
+ *
+ * @param source Python code
+ * @param filename name with which to label this console input (e.g. in error messages).
+ * @return true to indicate a partial statement was entered
+ */
+ public boolean runsource(String source, String filename) {
+ return false;
+ }
+
+ /**
+ * Compile and run some source in the interpreter, according to the {@link CompileMode} given.
+ * This method supports incremental compilation and interpretation through the return value,
+ * where {@code true} signifies that more input is expected in order to complete the Python
+ * statement. An interpreter can use this to decide whether to use {@code sys.ps1}
+ * ("{@code >>> }") or {@code sys.ps2} ("{@code ... }") to prompt the next line. The arguments
+ * are the same as the mandatory ones in the Python {@code compile()} command.
+ *
+ * One the following can happen:
+ *
+ * - The input is incorrect; compilation raised an exception (SyntaxError or OverflowError). A
+ * syntax traceback will be printed by calling {@link #showexception(PyException)}. Return is
+ * {@code false}.
+ *
+ * - The input is incomplete, and more input is required; compilation returned no code.
+ * Nothing happens. Return is {@code true}.
+ *
+ * - The input is complete; compilation returned a code object. The code is executed by
+ * calling {@link #runcode(PyObject)} (which also handles run-time exceptions, except for
+ * SystemExit). Return is {@code false}.
+ *
+ *
+ * @param source Python code
+ * @param filename name with which to label this console input (e.g. in error messages).
+ * @param kind of compilation required: {@link CompileMode#eval}, {@link CompileMode#exec} or
+ * {@link CompileMode#single}
+ * @return {@code true} to indicate a partial statement was provided
+ */
+ public boolean runsource(String source, String filename, CompileMode kind) {
+ return false;
+ }
+
+ /**
+ * Execute a code object. When an exception occurs, {@link #showexception(PyException)} is
+ * called to display a stack trace, except in the case of SystemExit, which is re-raised.
+ *
+ * A note about KeyboardInterrupt: this exception may occur elsewhere in this code, and may not
+ * always be caught. The caller should be prepared to deal with it.
+ **/
+
+ // Make this run in another thread somehow????
+ public void runcode(PyObject code) {
+ }
+
+ public void showexception(PyException exc) {
+ }
+
+ public void write(String data) {
+ }
+
+ public void resetbuffer() {
+ }
+}
diff --git a/java/ql/test/stubs/jython-2.7.2/org/python/util/PythonInterpreter.java b/java/ql/test/stubs/jython-2.7.2/org/python/util/PythonInterpreter.java
new file mode 100644
index 00000000000..92c50917b59
--- /dev/null
+++ b/java/ql/test/stubs/jython-2.7.2/org/python/util/PythonInterpreter.java
@@ -0,0 +1,252 @@
+package org.python.util;
+
+import java.io.Closeable;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.Properties;
+
+import org.python.core.PyCode;
+import org.python.core.PyObject;
+
+/**
+ * The PythonInterpreter class is a standard wrapper for a Jython interpreter for embedding in a
+ * Java application.
+ */
+public class PythonInterpreter implements Closeable {
+
+ /**
+ * Initializes the Jython runtime. This should only be called once, before any other Python
+ * objects (including PythonInterpreter) are created.
+ *
+ * @param preProperties A set of properties. Typically System.getProperties() is used.
+ * preProperties override properties from the registry file.
+ * @param postProperties Another set of properties. Values like python.home, python.path and all
+ * other values from the registry files can be added to this property set.
+ * postProperties override system properties and registry properties.
+ * @param argv Command line arguments, assigned to sys.argv.
+ */
+ public static void
+ initialize(Properties preProperties, Properties postProperties, String[] argv) {
+ }
+
+ /**
+ * Creates a new interpreter with an empty local namespace.
+ */
+ public PythonInterpreter() {
+ }
+
+ /**
+ * Creates a new interpreter with the ability to maintain a separate local namespace for each
+ * thread (set by invoking setLocals()).
+ *
+ * @param dict a Python mapping object (e.g., a dictionary) for use as the default namespace
+ */
+ public static PythonInterpreter threadLocalStateInterpreter(PyObject dict) {
+ return null;
+ }
+
+ /**
+ * Creates a new interpreter with a specified local namespace.
+ *
+ * @param dict a Python mapping object (e.g., a dictionary) for use as the namespace
+ */
+ public PythonInterpreter(PyObject dict) {
+ }
+
+ /**
+ * Sets a Python object to use for the standard output stream, sys.stdout. This
+ * stream is used in a byte-oriented way (mostly) that depends on the type of file-like object.
+ * The behaviour as implemented is:
+ *
+ * Stream behaviour for various object types
+ *
+ *
+ * Python type of object o written
+ *
+ *
+ *
+ * str/bytes
+ * unicode
+ * Any other type
+ *
+ *
+ * {@link PyFile}
+ * as bytes directly
+ * respect {@link PyFile#encoding}
+ * call str(o) first
+ *
+ *
+ * {@link PyFileWriter}
+ * each byte value as a char
+ * write as Java chars
+ * call o.toString() first
+ *
+ *
+ * Other {@link PyObject} f
+ * invoke f.write(str(o))
+ * invoke f.write(o)
+ * invoke f.write(str(o))
+ *
+ *
+ *
+ * @param outStream Python file-like object to use as the output stream
+ */
+ public void setOut(PyObject outStream) {
+ }
+
+ /**
+ * Sets a {@link java.io.Writer} to use for the standard output stream, sys.stdout.
+ * The behaviour as implemented is to output each object o by calling
+ * o.toString() and writing this as UTF-16.
+ *
+ * @param outStream to use as the output stream
+ */
+ public void setOut(java.io.Writer outStream) {
+ }
+
+ /**
+ * Sets a {@link java.io.OutputStream} to use for the standard output stream.
+ *
+ * @param outStream OutputStream to use as output stream
+ */
+ public void setOut(java.io.OutputStream outStream) {
+ }
+
+ /**
+ * Sets a Python object to use for the standard output stream, sys.stderr. This
+ * stream is used in a byte-oriented way (mostly) that depends on the type of file-like object,
+ * in the same way as {@link #setOut(PyObject)}.
+ *
+ * @param outStream Python file-like object to use as the error output stream
+ */
+ public void setErr(PyObject outStream) {
+ }
+
+ /**
+ * Sets a {@link java.io.Writer} to use for the standard output stream, sys.stdout.
+ * The behaviour as implemented is to output each object o by calling
+ * o.toString() and writing this as UTF-16.
+ *
+ * @param outStream to use as the error output stream
+ */
+ public void setErr(java.io.Writer outStream) {
+ }
+
+ public void setErr(java.io.OutputStream outStream) {
+ }
+
+ /**
+ * Evaluates a string as a Python expression and returns the result.
+ */
+ public PyObject eval(String s) {
+ return null;
+ }
+
+ /**
+ * Evaluates a Python code object and returns the result.
+ */
+ public PyObject eval(PyObject code) {
+ return null;
+ }
+
+ /**
+ * Executes a string of Python source in the local namespace.
+ *
+ * In some environments, such as Windows, Unicode characters in the script will be converted
+ * into ascii question marks (?). This can be avoided by first compiling the fragment using
+ * PythonInterpreter.compile(), and using the overridden form of this method which takes a
+ * PyCode object. Code page declarations are not supported.
+ */
+ public void exec(String s) {
+ }
+
+ /**
+ * Executes a Python code object in the local namespace.
+ */
+ public void exec(PyObject code) {
+ }
+
+ /**
+ * Executes a file of Python source in the local namespace.
+ */
+ public void execfile(String filename) {
+ }
+
+ public void execfile(java.io.InputStream s) {
+ }
+
+ public void execfile(java.io.InputStream s, String name) {
+ }
+
+ /**
+ * Compiles a string of Python source as either an expression (if possible) or a module.
+ *
+ * Designed for use by a JSR 223 implementation: "the Scripting API does not distinguish between
+ * scripts which return values and those which do not, nor do they make the corresponding
+ * distinction between evaluating or executing objects." (SCR.4.2.1)
+ */
+ public PyCode compile(String script) {
+ return null;
+ }
+
+ public PyCode compile(Reader reader) {
+ return null;
+ }
+
+ public PyCode compile(String script, String filename) {
+ return null;
+ }
+
+ public PyCode compile(Reader reader, String filename) {
+ return null;
+ }
+
+ /**
+ * Sets a variable in the local namespace.
+ *
+ * @param name the name of the variable
+ * @param value the object to set the variable to (as converted to an appropriate Python object)
+ */
+ public void set(String name, Object value) {
+ }
+
+ /**
+ * Sets a variable in the local namespace.
+ *
+ * @param name the name of the variable
+ * @param value the Python object to set the variable to
+ */
+ public void set(String name, PyObject value) {
+ }
+
+ /**
+ * Returns the value of a variable in the local namespace.
+ *
+ * @param name the name of the variable
+ * @return the value of the variable, or null if that name isn't assigned
+ */
+ public PyObject get(String name) {
+ return null;
+ }
+
+ /**
+ * Returns the value of a variable in the local namespace.
+ *
+ * The value will be returned as an instance of the given Java class.
+ * interp.get("foo", Object.class) will return the most appropriate generic Java
+ * object.
+ *
+ * @param name the name of the variable
+ * @param javaclass the class of object to return
+ * @return the value of the variable as the given class, or null if that name isn't assigned
+ */
+ public T get(String name, Class javaclass) {
+ return null;
+ }
+
+ public void cleanup() {
+ }
+
+ public void close() {
+ }
+}
diff --git a/java/ql/test/stubs/kryo-4.0.2/com/esotericsoftware/kryo/pool/KryoCallback.java b/java/ql/test/stubs/kryo-4.0.2/com/esotericsoftware/kryo/pool/KryoCallback.java
new file mode 100644
index 00000000000..729426aba62
--- /dev/null
+++ b/java/ql/test/stubs/kryo-4.0.2/com/esotericsoftware/kryo/pool/KryoCallback.java
@@ -0,0 +1,7 @@
+package com.esotericsoftware.kryo.pool;
+
+import com.esotericsoftware.kryo.Kryo;
+
+public interface KryoCallback {
+ T execute (Kryo kryo);
+}
diff --git a/java/ql/test/stubs/kryo-4.0.2/com/esotericsoftware/kryo/pool/KryoFactory.java b/java/ql/test/stubs/kryo-4.0.2/com/esotericsoftware/kryo/pool/KryoFactory.java
new file mode 100644
index 00000000000..4dcda1445df
--- /dev/null
+++ b/java/ql/test/stubs/kryo-4.0.2/com/esotericsoftware/kryo/pool/KryoFactory.java
@@ -0,0 +1,7 @@
+package com.esotericsoftware.kryo.pool;
+
+import com.esotericsoftware.kryo.Kryo;
+
+public interface KryoFactory {
+ Kryo create ();
+}
diff --git a/java/ql/test/stubs/kryo-4.0.2/com/esotericsoftware/kryo/pool/KryoPool.java b/java/ql/test/stubs/kryo-4.0.2/com/esotericsoftware/kryo/pool/KryoPool.java
new file mode 100644
index 00000000000..c005442c9e8
--- /dev/null
+++ b/java/ql/test/stubs/kryo-4.0.2/com/esotericsoftware/kryo/pool/KryoPool.java
@@ -0,0 +1,30 @@
+package com.esotericsoftware.kryo.pool;
+
+import com.esotericsoftware.kryo.Kryo;
+import java.util.Queue;
+
+public interface KryoPool {
+
+ Kryo borrow ();
+
+ void release (Kryo kryo);
+
+ T run (KryoCallback callback);
+
+ static class Builder {
+ public Builder (KryoFactory factory) {
+ }
+
+ public Builder queue (Queue queue) {
+ return null;
+ }
+
+ public Builder softReferences () {
+ return null;
+ }
+
+ public KryoPool build () {
+ return null;
+ }
+ }
+}
diff --git a/java/ql/test/stubs/scriptengine/javax/script/Bindings.java b/java/ql/test/stubs/scriptengine/javax/script/Bindings.java
new file mode 100644
index 00000000000..a8eeeb6fe5e
--- /dev/null
+++ b/java/ql/test/stubs/scriptengine/javax/script/Bindings.java
@@ -0,0 +1,14 @@
+package javax.script;
+import java.util.Map;
+
+public interface Bindings extends Map {
+ public Object put(String name, Object value);
+
+ public void putAll(Map extends String, ? extends Object> toMerge);
+
+ public boolean containsKey(Object key);
+
+ public Object get(Object key);
+
+ public Object remove(Object key);
+}
diff --git a/java/ql/test/stubs/scriptengine/javax/script/Compilable.java b/java/ql/test/stubs/scriptengine/javax/script/Compilable.java
new file mode 100644
index 00000000000..ce6700c5a66
--- /dev/null
+++ b/java/ql/test/stubs/scriptengine/javax/script/Compilable.java
@@ -0,0 +1,9 @@
+package javax.script;
+
+import java.io.Reader;
+
+public interface Compilable {
+ public CompiledScript compile(String script) throws ScriptException;
+
+ public CompiledScript compile(Reader script) throws ScriptException;
+}
diff --git a/java/ql/test/stubs/scriptengine/javax/script/CompiledScript.java b/java/ql/test/stubs/scriptengine/javax/script/CompiledScript.java
new file mode 100644
index 00000000000..2f03d58c9a7
--- /dev/null
+++ b/java/ql/test/stubs/scriptengine/javax/script/CompiledScript.java
@@ -0,0 +1,17 @@
+package javax.script;
+
+public abstract class CompiledScript {
+
+ public abstract Object eval(ScriptContext context) throws ScriptException;
+
+ public Object eval(Bindings bindings) throws ScriptException {
+ return null;
+ }
+
+ public Object eval() throws ScriptException {
+ return null;
+ }
+
+ public abstract ScriptEngine getEngine();
+
+}
\ No newline at end of file
diff --git a/java/ql/test/stubs/scriptengine/javax/script/ScriptEngine.java b/java/ql/test/stubs/scriptengine/javax/script/ScriptEngine.java
index 4dc4f8c3186..35b91119e4f 100644
--- a/java/ql/test/stubs/scriptengine/javax/script/ScriptEngine.java
+++ b/java/ql/test/stubs/scriptengine/javax/script/ScriptEngine.java
@@ -2,5 +2,7 @@ package javax.script;
public interface ScriptEngine {
Object eval(String var1) throws ScriptException;
+
+ public ScriptEngineFactory getFactory();
}
diff --git a/java/ql/test/stubs/scriptengine/javax/script/ScriptEngineFactory.java b/java/ql/test/stubs/scriptengine/javax/script/ScriptEngineFactory.java
index 7441c8a4ade..f802d86f80b 100644
--- a/java/ql/test/stubs/scriptengine/javax/script/ScriptEngineFactory.java
+++ b/java/ql/test/stubs/scriptengine/javax/script/ScriptEngineFactory.java
@@ -1,6 +1,11 @@
package javax.script;
public interface ScriptEngineFactory {
+ public String getEngineName();
+
+ public String getMethodCallSyntax(String obj, String m, String... args);
+
+ public String getProgram(String... statements);
+
ScriptEngine getScriptEngine();
}
-
diff --git a/java/ql/test/stubs/scriptengine/jdk/nashorn/api/scripting/ClassFilter.java b/java/ql/test/stubs/scriptengine/jdk/nashorn/api/scripting/ClassFilter.java
new file mode 100644
index 00000000000..fcc624fc106
--- /dev/null
+++ b/java/ql/test/stubs/scriptengine/jdk/nashorn/api/scripting/ClassFilter.java
@@ -0,0 +1,5 @@
+package jdk.nashorn.api.scripting;
+
+public interface ClassFilter {
+ public boolean exposeToScripts(String className);
+}
diff --git a/java/ql/test/stubs/scriptengine/jdk/nashorn/api/scripting/NashornScriptEngine.java b/java/ql/test/stubs/scriptengine/jdk/nashorn/api/scripting/NashornScriptEngine.java
index 8dc3c1afa10..e89282dfa27 100644
--- a/java/ql/test/stubs/scriptengine/jdk/nashorn/api/scripting/NashornScriptEngine.java
+++ b/java/ql/test/stubs/scriptengine/jdk/nashorn/api/scripting/NashornScriptEngine.java
@@ -1,10 +1,31 @@
package jdk.nashorn.api.scripting;
-import javax.script.*;
+import java.io.Reader;
-public final class NashornScriptEngine extends AbstractScriptEngine {
+import javax.script.AbstractScriptEngine;
+import javax.script.Compilable;
+import javax.script.CompiledScript;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineFactory;
+import javax.script.ScriptException;
+
+public final class NashornScriptEngine extends AbstractScriptEngine implements Compilable {
public Object eval(String var1) throws ScriptException {
return null;
}
-}
+ @Override
+ public ScriptEngineFactory getFactory() {
+ return null;
+ }
+
+ @Override
+ public CompiledScript compile(final Reader reader) throws ScriptException {
+ return null;
+ }
+
+ @Override
+ public CompiledScript compile(final String str) throws ScriptException {
+ return null;
+ }
+}
diff --git a/java/ql/test/stubs/scriptengine/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java b/java/ql/test/stubs/scriptengine/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java
index 763e098ddbe..177bf463eb3 100644
--- a/java/ql/test/stubs/scriptengine/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java
+++ b/java/ql/test/stubs/scriptengine/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java
@@ -3,20 +3,48 @@ package jdk.nashorn.api.scripting;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
-
public final class NashornScriptEngineFactory implements ScriptEngineFactory {
public NashornScriptEngineFactory() {
}
+ @Override
+ public String getEngineName() {
+ return null;
+ }
+ @Override
+ public String getMethodCallSyntax(final String obj, final String method, final String... args) {
+ return null;
+ }
+
+ @Override
+ public String getProgram(final String... statements) {
+ return null;
+ }
+
+ @Override
public ScriptEngine getScriptEngine() {
return null;
}
+ public ScriptEngine getScriptEngine(final ClassLoader appLoader) {
+ return null;
+ }
- public ScriptEngine getScriptEngine(String... args) {
+ public ScriptEngine getScriptEngine(final ClassFilter classFilter) {
+ return null;
+ }
+
+ public ScriptEngine getScriptEngine(final String... args) {
+ return null;
+ }
+
+ public ScriptEngine getScriptEngine(final String[] args, final ClassLoader appLoader) {
+ return null;
+ }
+
+ public ScriptEngine getScriptEngine(final String[] args, final ClassLoader appLoader, final ClassFilter classFilter) {
return null;
}
}
-
diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/servlet/ModelAndView.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/servlet/ModelAndView.java
new file mode 100644
index 00000000000..53e337d5053
--- /dev/null
+++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/servlet/ModelAndView.java
@@ -0,0 +1,107 @@
+package org.springframework.web.servlet;
+
+import java.util.Map;
+import org.springframework.http.HttpStatus;
+import org.springframework.lang.Nullable;
+
+public class ModelAndView {
+ @Nullable
+ private Object view;
+ @Nullable
+ private HttpStatus status;
+ private boolean cleared = false;
+
+ public ModelAndView() {
+ }
+
+ public ModelAndView(String viewName) {
+ this.view = viewName;
+ }
+
+ public ModelAndView(View view) {
+ this.view = view;
+ }
+
+ public ModelAndView(String viewName, @Nullable Map model) { }
+
+ public ModelAndView(View view, @Nullable Map model) { }
+
+ public ModelAndView(String viewName, HttpStatus status) { }
+
+ public ModelAndView(@Nullable String viewName, @Nullable Map model, @Nullable HttpStatus status) { }
+
+ public ModelAndView(String viewName, String modelName, Object modelObject) { }
+
+ public ModelAndView(View view, String modelName, Object modelObject) { }
+
+ public void setViewName(@Nullable String viewName) {
+ this.view = viewName;
+ }
+
+ @Nullable
+ public String getViewName() {
+ return "";
+ }
+
+ public void setView(@Nullable View view) { }
+
+ @Nullable
+ public View getView() {
+ return null;
+ }
+
+ public boolean hasView() {
+ return true;
+ }
+
+ public boolean isReference() {
+ return true;
+ }
+
+ @Nullable
+ protected Map getModelInternal() {
+ return null;
+ }
+
+ public Map getModel() {
+ return null;
+ }
+
+ public void setStatus(@Nullable HttpStatus status) { }
+
+ @Nullable
+ public HttpStatus getStatus() {
+ return this.status;
+ }
+
+ public ModelAndView addObject(String attributeName, @Nullable Object attributeValue) {
+ return null;
+ }
+
+ public ModelAndView addObject(Object attributeValue) {
+ return null;
+ }
+
+ public ModelAndView addAllObjects(@Nullable Map modelMap) {
+ return null;
+ }
+
+ public void clear() { }
+
+ public boolean isEmpty() {
+ return true;
+ }
+
+ public boolean wasCleared() {
+ return true;
+ }
+
+ public String toString() {
+ return "";
+ }
+
+ private String formatView() {
+ return "";
+ }
+}
+
diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/servlet/View.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/servlet/View.java
new file mode 100644
index 00000000000..b2281b8c250
--- /dev/null
+++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/servlet/View.java
@@ -0,0 +1,20 @@
+package org.springframework.web.servlet;
+
+import java.util.Map;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.lang.Nullable;
+
+public interface View {
+ String RESPONSE_STATUS_ATTRIBUTE = View.class.getName() + ".responseStatus";
+ String PATH_VARIABLES = View.class.getName() + ".pathVariables";
+ String SELECTED_CONTENT_TYPE = View.class.getName() + ".selectedContentType";
+
+ @Nullable
+ default String getContentType() {
+ return null;
+ }
+
+ void render(@Nullable Map var1, HttpServletRequest var2, HttpServletResponse var3) throws Exception;
+}
+
diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/servlet/view/AbstractUrlBasedView.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/servlet/view/AbstractUrlBasedView.java
new file mode 100644
index 00000000000..9efd87af12f
--- /dev/null
+++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/servlet/view/AbstractUrlBasedView.java
@@ -0,0 +1,39 @@
+package org.springframework.web.servlet.view;
+
+import java.util.Locale;
+import org.springframework.lang.Nullable;
+
+public abstract class AbstractUrlBasedView {
+ @Nullable
+ private String url;
+
+ protected AbstractUrlBasedView() { }
+
+ protected AbstractUrlBasedView(String url) {
+ this.url = url;
+ }
+
+ public void setUrl(@Nullable String url) {
+ this.url = url;
+ }
+
+ @Nullable
+ public String getUrl() {
+ return "";
+ }
+
+ public void afterPropertiesSet() throws Exception { }
+
+ protected boolean isUrlRequired() {
+ return true;
+ }
+
+ public boolean checkResource(Locale locale) throws Exception {
+ return true;
+ }
+
+ public String toString() {
+ return "";
+ }
+}
+
diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/servlet/view/RedirectView.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/servlet/view/RedirectView.java
new file mode 100644
index 00000000000..ee18868231a
--- /dev/null
+++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/servlet/view/RedirectView.java
@@ -0,0 +1,129 @@
+package org.springframework.web.servlet.view;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Array;
+import java.net.URLEncoder;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.http.HttpStatus;
+import org.springframework.lang.Nullable;
+
+public class RedirectView extends AbstractUrlBasedView {
+ private static final Pattern URI_TEMPLATE_VARIABLE_PATTERN = Pattern.compile("\\{([^/]+?)\\}");
+ private boolean contextRelative = false;
+ private boolean http10Compatible = true;
+ private boolean exposeModelAttributes = true;
+ @Nullable
+ private String encodingScheme;
+ @Nullable
+ private HttpStatus statusCode;
+ private boolean expandUriTemplateVariables = true;
+ private boolean propagateQueryParams = false;
+ @Nullable
+ private String[] hosts;
+
+ public RedirectView() { }
+
+ public RedirectView(String url) { }
+
+ public RedirectView(String url, boolean contextRelative) { }
+
+ public RedirectView(String url, boolean contextRelative, boolean http10Compatible) { }
+
+ public RedirectView(String url, boolean contextRelative, boolean http10Compatible, boolean exposeModelAttributes) { }
+
+ public void setContextRelative(boolean contextRelative) { }
+
+ public void setHttp10Compatible(boolean http10Compatible) { }
+
+ public void setExposeModelAttributes(boolean exposeModelAttributes) { }
+
+ public void setEncodingScheme(String encodingScheme) { }
+
+ public void setStatusCode(HttpStatus statusCode) { }
+
+ public void setExpandUriTemplateVariables(boolean expandUriTemplateVariables) { }
+
+ public void setPropagateQueryParams(boolean propagateQueryParams) { }
+
+ public boolean isPropagateQueryProperties() {
+ return true;
+ }
+
+ public void setHosts(@Nullable String... hosts) { }
+
+ @Nullable
+ public String[] getHosts() {
+ return this.hosts;
+ }
+
+ public boolean isRedirectView() {
+ return true;
+ }
+
+ protected boolean isContextRequired() {
+ return false;
+ }
+
+ protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) throws IOException { }
+
+ protected final String createTargetUrl(Map model, HttpServletRequest request) throws UnsupportedEncodingException {
+ return "";
+ }
+
+ private String getContextPath(HttpServletRequest request) {
+ return "";
+ }
+
+ protected StringBuilder replaceUriTemplateVariables(String targetUrl, Map model, Map currentUriVariables, String encodingScheme) throws UnsupportedEncodingException {
+ return null;
+ }
+
+ private Map getCurrentRequestUriVariables(HttpServletRequest request) {
+ return null;
+ }
+
+ protected void appendCurrentQueryParams(StringBuilder targetUrl, HttpServletRequest request) { }
+
+ protected void appendQueryProperties(StringBuilder targetUrl, Map model, String encodingScheme) throws UnsupportedEncodingException { }
+
+ protected Map queryProperties(Map model) {
+ return null;
+ }
+
+ protected boolean isEligibleProperty(String key, @Nullable Object value) {
+ return true;
+ }
+
+ protected boolean isEligibleValue(@Nullable Object value) {
+ return true;
+ }
+
+ protected String urlEncode(String input, String encodingScheme) throws UnsupportedEncodingException {
+ return "";
+ }
+
+ protected String updateTargetUrl(String targetUrl, Map model, HttpServletRequest request, HttpServletResponse response) {
+ return "";
+ }
+
+ protected void sendRedirect(HttpServletRequest request, HttpServletResponse response, String targetUrl, boolean http10Compatible) throws IOException { }
+
+ protected boolean isRemoteHost(String targetUrl) {
+ return true;
+ }
+
+ protected HttpStatus getHttp11StatusCode(HttpServletRequest request, HttpServletResponse response, String targetUrl) {
+ return this.statusCode;
+ }
+}
+
diff --git a/javascript/change-notes/2021-05-18-clone.md b/javascript/change-notes/2021-05-18-clone.md
new file mode 100644
index 00000000000..42d52d72a3d
--- /dev/null
+++ b/javascript/change-notes/2021-05-18-clone.md
@@ -0,0 +1,4 @@
+lgtm,codescanning
+* The dataflow libraries now model dataflow in the `clone` library.
+ Affected packages are
+ [clone](https://npmjs.com/package/clone)
diff --git a/javascript/ql/src/Summary/LinesOfCode.ql b/javascript/ql/src/Summary/LinesOfCode.ql
index 9f89e0e2163..cadf0a9cf8f 100644
--- a/javascript/ql/src/Summary/LinesOfCode.ql
+++ b/javascript/ql/src/Summary/LinesOfCode.ql
@@ -4,6 +4,7 @@
* @description The total number of lines of JavaScript or TypeScript code across all files checked into the repository, except in `node_modules`. This is a useful metric of the size of a database. For all files that were seen during extraction, this query counts the lines of code, excluding whitespace or comments.
* @kind metric
* @tags summary
+ * lines-of-code
*/
import javascript
diff --git a/javascript/ql/src/Summary/TaintSinks.ql b/javascript/ql/src/Summary/TaintSinks.ql
new file mode 100644
index 00000000000..2da65398935
--- /dev/null
+++ b/javascript/ql/src/Summary/TaintSinks.ql
@@ -0,0 +1,15 @@
+/**
+ * @name Taint sinks
+ * @description Expressions that are vulnerable if containing untrusted data.
+ * @kind problem
+ * @problem.severity info
+ * @id js/summary/taint-sinks
+ * @tags summary
+ * @precision medium
+ */
+
+import javascript
+import meta.internal.TaintMetrics
+
+from string kind
+select relevantTaintSink(kind), kind + " sink"
diff --git a/javascript/ql/src/Summary/TaintSources.ql b/javascript/ql/src/Summary/TaintSources.ql
new file mode 100644
index 00000000000..78e544f0bd5
--- /dev/null
+++ b/javascript/ql/src/Summary/TaintSources.ql
@@ -0,0 +1,16 @@
+/**
+ * @name Taint sources
+ * @description Sources of untrusted input.
+ * @kind problem
+ * @problem.severity info
+ * @id js/summary/taint-sources
+ * @tags summary
+ * @precision medium
+ */
+
+import javascript
+import meta.internal.TaintMetrics
+
+from RemoteFlowSource node
+where node = relevantTaintSource()
+select node, node.getSourceType()
diff --git a/javascript/ql/src/meta/internal/TaintMetrics.qll b/javascript/ql/src/meta/internal/TaintMetrics.qll
index 6d10b2c6ad6..f6eae2eaa6e 100644
--- a/javascript/ql/src/meta/internal/TaintMetrics.qll
+++ b/javascript/ql/src/meta/internal/TaintMetrics.qll
@@ -75,16 +75,9 @@ DataFlow::Node relevantTaintSink(string kind) {
DataFlow::Node relevantTaintSink() { result = relevantTaintSink(_) }
/**
- * Gets a remote flow source or `document.location` source.
+ * Gets a relevant remote flow source.
*/
-DataFlow::Node relevantTaintSource() {
- not result.getFile() instanceof IgnoredFile and
- (
- result instanceof RemoteFlowSource
- or
- result = DOM::locationSource()
- )
-}
+RemoteFlowSource relevantTaintSource() { not result.getFile() instanceof IgnoredFile }
/**
* Gets the output of a call that shows intent to sanitize a value
diff --git a/javascript/ql/src/semmle/javascript/ApiGraphs.qll b/javascript/ql/src/semmle/javascript/ApiGraphs.qll
index 385dc1e76d3..590142590a4 100644
--- a/javascript/ql/src/semmle/javascript/ApiGraphs.qll
+++ b/javascript/ql/src/semmle/javascript/ApiGraphs.qll
@@ -183,6 +183,11 @@ module API {
*/
Node getPromised() { result = getASuccessor(Label::promised()) }
+ /**
+ * Gets a node representing the error wrapped in the `Promise` object represented by this node.
+ */
+ Node getPromisedError() { result = getASuccessor(Label::promisedError()) }
+
/**
* Gets a string representation of the lexicographically least among all shortest access paths
* from the root to this node.
@@ -468,6 +473,9 @@ module API {
or
lbl = Label::promised() and
PromiseFlow::storeStep(rhs, pred, Promises::valueProp())
+ or
+ lbl = Label::promisedError() and
+ PromiseFlow::storeStep(rhs, pred, Promises::errorProp())
)
or
exists(DataFlow::ClassNode cls, string name |
@@ -482,6 +490,12 @@ module API {
rhs = f.getAReturn()
)
or
+ exists(DataFlow::FunctionNode f |
+ base = MkAsyncFuncResult(f) and
+ lbl = Label::promisedError() and
+ rhs = f.getExceptionalReturn()
+ )
+ or
exists(int i |
lbl = Label::parameter(i) and
argumentPassing(base, i, rhs)
@@ -559,6 +573,9 @@ module API {
or
lbl = Label::promised() and
PromiseFlow::loadStep(pred, ref, Promises::valueProp())
+ or
+ lbl = Label::promisedError() and
+ PromiseFlow::loadStep(pred, ref, Promises::errorProp())
)
or
exists(DataFlow::Node def, DataFlow::FunctionNode fn |
@@ -962,6 +979,9 @@ private module Label {
/** Gets the `promised` edge label connecting a promise to its contained value. */
string promised() { result = "promised" }
+
+ /** Gets the `promisedError` edge label connecting a promise to its rejected value. */
+ string promisedError() { result = "promisedError" }
}
private class NodeModuleSourcesNodes extends DataFlow::SourceNode::Range {
diff --git a/javascript/ql/src/semmle/javascript/Extend.qll b/javascript/ql/src/semmle/javascript/Extend.qll
index 9b7255983b9..d50054fc4ee 100644
--- a/javascript/ql/src/semmle/javascript/Extend.qll
+++ b/javascript/ql/src/semmle/javascript/Extend.qll
@@ -174,3 +174,17 @@ private class ExtendCallTaintStep extends TaintTracking::SharedTaintStep {
)
}
}
+
+private import semmle.javascript.dataflow.internal.PreCallGraphStep
+
+/**
+ * A step for the `clone` package.
+ */
+private class CloneStep extends PreCallGraphStep {
+ override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
+ exists(DataFlow::CallNode call | call = DataFlow::moduleImport("clone").getACall() |
+ pred = call.getArgument(0) and
+ succ = call
+ )
+ }
+}
diff --git a/javascript/ql/src/semmle/javascript/PrintAst.qll b/javascript/ql/src/semmle/javascript/PrintAst.qll
index 0499e3bd547..029cfd536fc 100644
--- a/javascript/ql/src/semmle/javascript/PrintAst.qll
+++ b/javascript/ql/src/semmle/javascript/PrintAst.qll
@@ -73,7 +73,12 @@ private newtype TPrintAstNode =
THTMLAttributesNodes(HTML::Element e) { shouldPrint(e, _) and not isNotNeeded(e) } or
THTMLAttributeNode(HTML::Attribute attr) { shouldPrint(attr, _) and not isNotNeeded(attr) } or
THTMLScript(Script script) { shouldPrint(script, _) and not isNotNeeded(script) } or
- THTMLCodeInAttr(CodeInAttribute attr) { shouldPrint(attr, _) and not isNotNeeded(attr) }
+ THTMLCodeInAttr(CodeInAttribute attr) { shouldPrint(attr, _) and not isNotNeeded(attr) } or
+ TRegExpTermNode(RegExpTerm term) {
+ shouldPrint(term, _) and
+ term.isUsedAsRegExp() and
+ any(RegExpLiteral lit).getRoot() = term.getRootTerm()
+ }
/**
* A node in the output tree.
@@ -282,6 +287,39 @@ private module PrintJavaScript {
}
}
+ /**
+ * A print node for regexp literals.
+ *
+ * The single child of this node is the root `RegExpTerm`.
+ */
+ class RegexpNode extends ElementNode {
+ override RegExpLiteral element;
+
+ override PrintAstNode getChild(int childIndex) {
+ childIndex = 0 and
+ result.(RegExpTermNode).getTerm() = element.getRoot()
+ }
+ }
+
+ /**
+ * A print node for regexp terms.
+ */
+ class RegExpTermNode extends PrintAstNode, TRegExpTermNode {
+ RegExpTerm term;
+
+ RegExpTermNode() { this = TRegExpTermNode(term) }
+
+ RegExpTerm getTerm() { result = term }
+
+ override PrintAstNode getChild(int childIndex) {
+ result.(RegExpTermNode).getTerm() = term.getChild(childIndex)
+ }
+
+ override string toString() { result = getQlClass(term) + term.toString() }
+
+ override Location getLocation() { result = term.getLocation() }
+ }
+
/**
* An aggregate node representing all the arguments for an function invocation.
*/
diff --git a/javascript/ql/src/semmle/javascript/Regexp.qll b/javascript/ql/src/semmle/javascript/Regexp.qll
index a34b052005d..d3b7e9cac7e 100644
--- a/javascript/ql/src/semmle/javascript/Regexp.qll
+++ b/javascript/ql/src/semmle/javascript/Regexp.qll
@@ -215,7 +215,9 @@ class InfiniteRepetitionQuantifier extends RegExpQuantifier {
* \w
* ```
*/
-class RegExpEscape extends RegExpTerm, @regexp_escape { }
+class RegExpEscape extends RegExpTerm, @regexp_escape {
+ override string getAPrimaryQlClass() { result = "RegExpEscape" }
+}
/**
* A constant regular expression term, that is, a regular expression
@@ -240,6 +242,8 @@ class RegExpConstant extends RegExpTerm, @regexp_constant {
override predicate isNullable() { none() }
override string getConstantValue() { result = getValue() }
+
+ override string getAPrimaryQlClass() { result = "RegExpConstant" }
}
/**
@@ -264,6 +268,8 @@ class RegExpCharEscape extends RegExpEscape, RegExpConstant, @regexp_char_escape
)
)
}
+
+ override string getAPrimaryQlClass() { result = "RegExpCharEscape" }
}
/**
@@ -285,6 +291,8 @@ class RegExpAlt extends RegExpTerm, @regexp_alt {
override predicate isNullable() { getAlternative().isNullable() }
override string getAMatchedString() { result = getAlternative().getAMatchedString() }
+
+ override string getAPrimaryQlClass() { result = "RegExpAlt" }
}
/**
@@ -332,6 +340,8 @@ class RegExpSequence extends RegExpTerm, @regexp_seq {
result = this.getChild(i + 1)
)
}
+
+ override string getAPrimaryQlClass() { result = "RegExpSequence" }
}
/**
@@ -346,6 +356,8 @@ class RegExpSequence extends RegExpTerm, @regexp_seq {
*/
class RegExpAnchor extends RegExpTerm, @regexp_anchor {
override predicate isNullable() { any() }
+
+ override string getAPrimaryQlClass() { result = "RegExpAnchor" }
}
/**
@@ -357,7 +369,9 @@ class RegExpAnchor extends RegExpTerm, @regexp_anchor {
* ^
* ```
*/
-class RegExpCaret extends RegExpAnchor, @regexp_caret { }
+class RegExpCaret extends RegExpAnchor, @regexp_caret {
+ override string getAPrimaryQlClass() { result = "RegExpCaret" }
+}
/**
* A dollar assertion `$` matching the end of a line.
@@ -368,7 +382,9 @@ class RegExpCaret extends RegExpAnchor, @regexp_caret { }
* $
* ```
*/
-class RegExpDollar extends RegExpAnchor, @regexp_dollar { }
+class RegExpDollar extends RegExpAnchor, @regexp_dollar {
+ override string getAPrimaryQlClass() { result = "RegExpDollar" }
+}
/**
* A word boundary assertion.
@@ -381,6 +397,8 @@ class RegExpDollar extends RegExpAnchor, @regexp_dollar { }
*/
class RegExpWordBoundary extends RegExpTerm, @regexp_wordboundary {
override predicate isNullable() { any() }
+
+ override string getAPrimaryQlClass() { result = "RegExpWordBoundary" }
}
/**
@@ -394,6 +412,8 @@ class RegExpWordBoundary extends RegExpTerm, @regexp_wordboundary {
*/
class RegExpNonWordBoundary extends RegExpTerm, @regexp_nonwordboundary {
override predicate isNullable() { any() }
+
+ override string getAPrimaryQlClass() { result = "RegExpNonWordBoundary" }
}
/**
@@ -425,7 +445,9 @@ class RegExpSubPattern extends RegExpTerm, @regexp_subpattern {
* (?!\n)
* ```
*/
-class RegExpLookahead extends RegExpSubPattern, @regexp_lookahead { }
+class RegExpLookahead extends RegExpSubPattern, @regexp_lookahead {
+ override string getAPrimaryQlClass() { result = "RegExpLookahead" }
+}
/**
* A zero-width lookbehind assertion.
@@ -437,7 +459,9 @@ class RegExpLookahead extends RegExpSubPattern, @regexp_lookahead { }
* (?`
@@ -770,6 +832,8 @@ class RegExpBackRef extends RegExpTerm, @regexp_backref {
}
override predicate isNullable() { getGroup().isNullable() }
+
+ override string getAPrimaryQlClass() { result = "RegExpBackRef" }
}
/**
@@ -808,6 +872,8 @@ class RegExpCharacterClass extends RegExpTerm, @regexp_char_class {
cce1 != cce2 and cce1.toLowerCase() = cce2.toLowerCase()
)
}
+
+ override string getAPrimaryQlClass() { result = "RegExpCharacterClass" }
}
/**
@@ -827,6 +893,8 @@ class RegExpCharacterRange extends RegExpTerm, @regexp_char_range {
lo = getChild(0).(RegExpConstant).getValue() and
hi = getChild(1).(RegExpConstant).getValue()
}
+
+ override string getAPrimaryQlClass() { result = "RegExpCharacterRange" }
}
/** A parse error encountered while processing a regular expression literal. */
diff --git a/javascript/ql/src/semmle/javascript/TypeScript.qll b/javascript/ql/src/semmle/javascript/TypeScript.qll
index 4fe263c8389..0b611140449 100644
--- a/javascript/ql/src/semmle/javascript/TypeScript.qll
+++ b/javascript/ql/src/semmle/javascript/TypeScript.qll
@@ -725,7 +725,7 @@ class TypeAccess extends @typeaccess, TypeExpr, TypeRef {
spec.getImportedName() = exportedName and
this = spec.getLocal().(TypeDecl).getLocalTypeName().getAnAccess()
or
- spec instanceof ImportNamespaceSpecifier and
+ (spec instanceof ImportNamespaceSpecifier or spec instanceof ImportDefaultSpecifier) and
this =
spec.getLocal().(LocalNamespaceDecl).getLocalNamespaceName().getAMemberAccess(exportedName)
)
diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll
index c73c894ca4b..f02e9b0f287 100644
--- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll
+++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll
@@ -239,7 +239,6 @@ module DataFlow {
private TypeAnnotation getFallbackTypeAnnotation() {
exists(BindingPattern pattern |
this = valueNode(pattern) and
- not ast_node_type(pattern, _) and
result = pattern.getTypeAnnotation()
)
or
diff --git a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll
index 451ad3f24d2..18204c5b59b 100644
--- a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll
+++ b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll
@@ -206,19 +206,14 @@ module ClientRequest {
/**
* A model of a URL request made using the `axios` library.
*/
- class AxiosUrlRequest extends ClientRequest::Range {
+ class AxiosUrlRequest extends ClientRequest::Range, API::CallNode {
string method;
AxiosUrlRequest() {
- exists(string moduleName, DataFlow::SourceNode callee | this = callee.getACall() |
- moduleName = "axios" and
- (
- callee = DataFlow::moduleImport(moduleName) and method = "request"
- or
- callee = DataFlow::moduleMember(moduleName, method) and
- (method = httpMethodName() or method = "request")
- )
- )
+ this = API::moduleImport("axios").getACall() and method = "request"
+ or
+ this = API::moduleImport("axios").getMember(method).getACall() and
+ method = [httpMethodName(), "request"]
}
private int getOptionsArgIndex() {
@@ -247,12 +242,10 @@ module ClientRequest {
method = "request" and
result = getOptionArgument(0, "data")
or
- (method = "post" or method = "put" or method = "put") and
- (result = getArgument(1) or result = getOptionArgument(2, "data"))
+ method = ["post", "put"] and
+ result = [getArgument(1), getOptionArgument(2, "data")]
or
- exists(string name | name = "headers" or name = "params" |
- result = getOptionArgument([0 .. 2], name)
- )
+ result = getOptionArgument([0 .. 2], ["headers", "params"])
}
/** Gets the response type from the options passed in. */
@@ -275,6 +268,10 @@ module ClientRequest {
responseType = getResponseType() and
promise = true and
result = this
+ or
+ responseType = getResponseType() and
+ promise = false and
+ result = getReturn().getPromisedError().getMember("response").getAnImmediateUse()
}
}
diff --git a/javascript/ql/src/semmle/javascript/security/internal/SensitiveDataHeuristics.qll b/javascript/ql/src/semmle/javascript/security/internal/SensitiveDataHeuristics.qll
index ddf95b1b534..589c37120b9 100644
--- a/javascript/ql/src/semmle/javascript/security/internal/SensitiveDataHeuristics.qll
+++ b/javascript/ql/src/semmle/javascript/security/internal/SensitiveDataHeuristics.qll
@@ -58,7 +58,8 @@ module HeuristicNames {
*/
string maybeAccountInfo() {
result = "(?is).*acc(ou)?nt.*" or
- result = "(?is).*(puid|username|userid).*"
+ result = "(?is).*(puid|username|userid).*" or
+ result = "(?s).*([uU]|^|_|[a-z](?=U))([uU][iI][dD]).*"
}
/**
diff --git a/javascript/ql/test/library-tests/TypeScript/HasUnderlyingType/HasUnderlyingType.expected b/javascript/ql/test/library-tests/TypeScript/HasUnderlyingType/HasUnderlyingType.expected
index 95c6d7e03d9..47e57e0a242 100644
--- a/javascript/ql/test/library-tests/TypeScript/HasUnderlyingType/HasUnderlyingType.expected
+++ b/javascript/ql/test/library-tests/TypeScript/HasUnderlyingType/HasUnderlyingType.expected
@@ -1,2 +1,6 @@
+underlyingTypeNode
+| foo | Bar | foo.ts:3:1:5:1 | use (instance (member Bar (member exports (module foo)))) |
+| foo | Bar | foo.ts:3:12:3:12 | use (instance (member Bar (member exports (module foo)))) |
+#select
| tst.ts:8:14:8:16 | arg | Base in global scope |
| tst.ts:8:14:8:16 | arg | Sub in global scope |
diff --git a/javascript/ql/test/library-tests/TypeScript/HasUnderlyingType/HasUnderlyingType.ql b/javascript/ql/test/library-tests/TypeScript/HasUnderlyingType/HasUnderlyingType.ql
index 77e311b3b76..72d4e6d0f3d 100644
--- a/javascript/ql/test/library-tests/TypeScript/HasUnderlyingType/HasUnderlyingType.ql
+++ b/javascript/ql/test/library-tests/TypeScript/HasUnderlyingType/HasUnderlyingType.ql
@@ -3,3 +3,7 @@ import javascript
from Expr e, TypeName typeName
where e.getType().hasUnderlyingTypeName(typeName)
select e, typeName
+
+query API::Node underlyingTypeNode(string mod, string name) {
+ result = API::Node::ofType(mod, name)
+}
diff --git a/javascript/ql/test/library-tests/TypeScript/HasUnderlyingType/foo.ts b/javascript/ql/test/library-tests/TypeScript/HasUnderlyingType/foo.ts
new file mode 100644
index 00000000000..1b5be79068a
--- /dev/null
+++ b/javascript/ql/test/library-tests/TypeScript/HasUnderlyingType/foo.ts
@@ -0,0 +1,5 @@
+import foo from "foo";
+
+function f(x: foo.Bar) {
+ return x;
+}
diff --git a/javascript/ql/test/library-tests/TypeScript/Types/dummy.ts b/javascript/ql/test/library-tests/TypeScript/Types/dummy.ts
index 77f17538e18..d36be434986 100644
--- a/javascript/ql/test/library-tests/TypeScript/Types/dummy.ts
+++ b/javascript/ql/test/library-tests/TypeScript/Types/dummy.ts
@@ -1,2 +1,4 @@
// Dummy file to be imported so the other files are seen as modules.
export let x = 5;
+
+export let reg = /ab+c/;
\ No newline at end of file
diff --git a/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected b/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected
index bd50eaa28ec..1f39b308479 100644
--- a/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected
+++ b/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected
@@ -74,6 +74,17 @@ nodes
| dummy.ts:2:12:2:12 | [VarDecl] x | semmle.label | [VarDecl] x |
| dummy.ts:2:12:2:16 | [VariableDeclarator] x = 5 | semmle.label | [VariableDeclarator] x = 5 |
| dummy.ts:2:16:2:16 | [Literal] 5 | semmle.label | [Literal] 5 |
+| dummy.ts:4:1:4:24 | [ExportDeclaration] export ... /ab+c/; | semmle.label | [ExportDeclaration] export ... /ab+c/; |
+| dummy.ts:4:1:4:24 | [ExportDeclaration] export ... /ab+c/; | semmle.order | 13 |
+| dummy.ts:4:8:4:24 | [DeclStmt] let reg = ... | semmle.label | [DeclStmt] let reg = ... |
+| dummy.ts:4:12:4:14 | [VarDecl] reg | semmle.label | [VarDecl] reg |
+| dummy.ts:4:12:4:23 | [VariableDeclarator] reg = /ab+c/ | semmle.label | [VariableDeclarator] reg = /ab+c/ |
+| dummy.ts:4:18:4:23 | [RegExpLiteral] /ab+c/ | semmle.label | [RegExpLiteral] /ab+c/ |
+| dummy.ts:4:19:4:19 | [RegExpNormalConstant] a | semmle.label | [RegExpNormalConstant] a |
+| dummy.ts:4:19:4:22 | [RegExpSequence] ab+c | semmle.label | [RegExpSequence] ab+c |
+| dummy.ts:4:20:4:20 | [RegExpNormalConstant] b | semmle.label | [RegExpNormalConstant] b |
+| dummy.ts:4:20:4:21 | [RegExpPlus] b+ | semmle.label | [RegExpPlus] b+ |
+| dummy.ts:4:22:4:22 | [RegExpNormalConstant] c | semmle.label | [RegExpNormalConstant] c |
| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
@@ -85,7 +96,7 @@ nodes
| file://:0:0:0:0 | (TypeParameters) | semmle.label | (TypeParameters) |
| file://:0:0:0:0 | (TypeParameters) | semmle.label | (TypeParameters) |
| middle-rest.ts:1:1:1:40 | [DeclStmt] let foo = ... | semmle.label | [DeclStmt] let foo = ... |
-| middle-rest.ts:1:1:1:40 | [DeclStmt] let foo = ... | semmle.order | 13 |
+| middle-rest.ts:1:1:1:40 | [DeclStmt] let foo = ... | semmle.order | 14 |
| middle-rest.ts:1:5:1:7 | [VarDecl] foo | semmle.label | [VarDecl] foo |
| middle-rest.ts:1:5:1:39 | [VariableDeclarator] foo: [b ... number] | semmle.label | [VariableDeclarator] foo: [b ... number] |
| middle-rest.ts:1:10:1:39 | [TupleTypeExpr] [boolea ... number] | semmle.label | [TupleTypeExpr] [boolea ... number] |
@@ -97,55 +108,55 @@ nodes
| middle-rest.ts:3:1:3:3 | [VarRef] foo | semmle.label | [VarRef] foo |
| middle-rest.ts:3:1:3:26 | [AssignExpr] foo = [ ... ", 123] | semmle.label | [AssignExpr] foo = [ ... ", 123] |
| middle-rest.ts:3:1:3:27 | [ExprStmt] foo = [ ... , 123]; | semmle.label | [ExprStmt] foo = [ ... , 123]; |
-| middle-rest.ts:3:1:3:27 | [ExprStmt] foo = [ ... , 123]; | semmle.order | 14 |
+| middle-rest.ts:3:1:3:27 | [ExprStmt] foo = [ ... , 123]; | semmle.order | 15 |
| middle-rest.ts:3:7:3:26 | [ArrayExpr] [true, "hello", 123] | semmle.label | [ArrayExpr] [true, "hello", 123] |
| middle-rest.ts:3:8:3:11 | [Literal] true | semmle.label | [Literal] true |
| middle-rest.ts:3:14:3:20 | [Literal] "hello" | semmle.label | [Literal] "hello" |
| middle-rest.ts:3:23:3:25 | [Literal] 123 | semmle.label | [Literal] 123 |
| tst.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.label | [ImportDeclaration] import ... dummy"; |
-| tst.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 15 |
+| tst.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 16 |
| tst.ts:1:8:1:17 | [ImportSpecifier] * as dummy | semmle.label | [ImportSpecifier] * as dummy |
| tst.ts:1:13:1:17 | [VarDecl] dummy | semmle.label | [VarDecl] dummy |
| tst.ts:1:24:1:32 | [Literal] "./dummy" | semmle.label | [Literal] "./dummy" |
| tst.ts:3:1:3:19 | [DeclStmt] var numVar = ... | semmle.label | [DeclStmt] var numVar = ... |
-| tst.ts:3:1:3:19 | [DeclStmt] var numVar = ... | semmle.order | 16 |
+| tst.ts:3:1:3:19 | [DeclStmt] var numVar = ... | semmle.order | 17 |
| tst.ts:3:5:3:10 | [VarDecl] numVar | semmle.label | [VarDecl] numVar |
| tst.ts:3:5:3:18 | [VariableDeclarator] numVar: number | semmle.label | [VariableDeclarator] numVar: number |
| tst.ts:3:13:3:18 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number |
| tst.ts:5:1:5:18 | [DeclStmt] var num1 = ... | semmle.label | [DeclStmt] var num1 = ... |
-| tst.ts:5:1:5:18 | [DeclStmt] var num1 = ... | semmle.order | 17 |
+| tst.ts:5:1:5:18 | [DeclStmt] var num1 = ... | semmle.order | 18 |
| tst.ts:5:5:5:8 | [VarDecl] num1 | semmle.label | [VarDecl] num1 |
| tst.ts:5:5:5:17 | [VariableDeclarator] num1 = numVar | semmle.label | [VariableDeclarator] num1 = numVar |
| tst.ts:5:12:5:17 | [VarRef] numVar | semmle.label | [VarRef] numVar |
| tst.ts:6:1:6:13 | [DeclStmt] var num2 = ... | semmle.label | [DeclStmt] var num2 = ... |
-| tst.ts:6:1:6:13 | [DeclStmt] var num2 = ... | semmle.order | 18 |
+| tst.ts:6:1:6:13 | [DeclStmt] var num2 = ... | semmle.order | 19 |
| tst.ts:6:5:6:8 | [VarDecl] num2 | semmle.label | [VarDecl] num2 |
| tst.ts:6:5:6:12 | [VariableDeclarator] num2 = 5 | semmle.label | [VariableDeclarator] num2 = 5 |
| tst.ts:6:12:6:12 | [Literal] 5 | semmle.label | [Literal] 5 |
| tst.ts:7:1:7:23 | [DeclStmt] var num3 = ... | semmle.label | [DeclStmt] var num3 = ... |
-| tst.ts:7:1:7:23 | [DeclStmt] var num3 = ... | semmle.order | 19 |
+| tst.ts:7:1:7:23 | [DeclStmt] var num3 = ... | semmle.order | 20 |
| tst.ts:7:5:7:8 | [VarDecl] num3 | semmle.label | [VarDecl] num3 |
| tst.ts:7:5:7:22 | [VariableDeclarator] num3 = num1 + num2 | semmle.label | [VariableDeclarator] num3 = num1 + num2 |
| tst.ts:7:12:7:15 | [VarRef] num1 | semmle.label | [VarRef] num1 |
| tst.ts:7:12:7:22 | [BinaryExpr] num1 + num2 | semmle.label | [BinaryExpr] num1 + num2 |
| tst.ts:7:19:7:22 | [VarRef] num2 | semmle.label | [VarRef] num2 |
| tst.ts:9:1:9:19 | [DeclStmt] var strVar = ... | semmle.label | [DeclStmt] var strVar = ... |
-| tst.ts:9:1:9:19 | [DeclStmt] var strVar = ... | semmle.order | 20 |
+| tst.ts:9:1:9:19 | [DeclStmt] var strVar = ... | semmle.order | 21 |
| tst.ts:9:5:9:10 | [VarDecl] strVar | semmle.label | [VarDecl] strVar |
| tst.ts:9:5:9:18 | [VariableDeclarator] strVar: string | semmle.label | [VariableDeclarator] strVar: string |
| tst.ts:9:13:9:18 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string |
| tst.ts:10:1:10:20 | [DeclStmt] var hello = ... | semmle.label | [DeclStmt] var hello = ... |
-| tst.ts:10:1:10:20 | [DeclStmt] var hello = ... | semmle.order | 21 |
+| tst.ts:10:1:10:20 | [DeclStmt] var hello = ... | semmle.order | 22 |
| tst.ts:10:5:10:9 | [VarDecl] hello | semmle.label | [VarDecl] hello |
| tst.ts:10:5:10:19 | [VariableDeclarator] hello = "hello" | semmle.label | [VariableDeclarator] hello = "hello" |
| tst.ts:10:13:10:19 | [Literal] "hello" | semmle.label | [Literal] "hello" |
| tst.ts:11:1:11:20 | [DeclStmt] var world = ... | semmle.label | [DeclStmt] var world = ... |
-| tst.ts:11:1:11:20 | [DeclStmt] var world = ... | semmle.order | 22 |
+| tst.ts:11:1:11:20 | [DeclStmt] var world = ... | semmle.order | 23 |
| tst.ts:11:5:11:9 | [VarDecl] world | semmle.label | [VarDecl] world |
| tst.ts:11:5:11:19 | [VariableDeclarator] world = "world" | semmle.label | [VariableDeclarator] world = "world" |
| tst.ts:11:13:11:19 | [Literal] "world" | semmle.label | [Literal] "world" |
| tst.ts:12:1:12:30 | [DeclStmt] var msg = ... | semmle.label | [DeclStmt] var msg = ... |
-| tst.ts:12:1:12:30 | [DeclStmt] var msg = ... | semmle.order | 23 |
+| tst.ts:12:1:12:30 | [DeclStmt] var msg = ... | semmle.order | 24 |
| tst.ts:12:5:12:7 | [VarDecl] msg | semmle.label | [VarDecl] msg |
| tst.ts:12:5:12:29 | [VariableDeclarator] msg = h ... + world | semmle.label | [VariableDeclarator] msg = h ... + world |
| tst.ts:12:11:12:15 | [VarRef] hello | semmle.label | [VarRef] hello |
@@ -154,7 +165,7 @@ nodes
| tst.ts:12:19:12:21 | [Literal] " " | semmle.label | [Literal] " " |
| tst.ts:12:25:12:29 | [VarRef] world | semmle.label | [VarRef] world |
| tst.ts:14:1:14:63 | [FunctionDeclStmt] functio ... + y; } | semmle.label | [FunctionDeclStmt] functio ... + y; } |
-| tst.ts:14:1:14:63 | [FunctionDeclStmt] functio ... + y; } | semmle.order | 24 |
+| tst.ts:14:1:14:63 | [FunctionDeclStmt] functio ... + y; } | semmle.order | 25 |
| tst.ts:14:10:14:15 | [VarDecl] concat | semmle.label | [VarDecl] concat |
| tst.ts:14:17:14:17 | [SimpleParameter] x | semmle.label | [SimpleParameter] x |
| tst.ts:14:20:14:25 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string |
@@ -167,7 +178,7 @@ nodes
| tst.ts:14:56:14:60 | [BinaryExpr] x + y | semmle.label | [BinaryExpr] x + y |
| tst.ts:14:60:14:60 | [VarRef] y | semmle.label | [VarRef] y |
| tst.ts:16:1:16:60 | [FunctionDeclStmt] functio ... + y; } | semmle.label | [FunctionDeclStmt] functio ... + y; } |
-| tst.ts:16:1:16:60 | [FunctionDeclStmt] functio ... + y; } | semmle.order | 25 |
+| tst.ts:16:1:16:60 | [FunctionDeclStmt] functio ... + y; } | semmle.order | 26 |
| tst.ts:16:10:16:12 | [VarDecl] add | semmle.label | [VarDecl] add |
| tst.ts:16:14:16:14 | [SimpleParameter] x | semmle.label | [SimpleParameter] x |
| tst.ts:16:17:16:22 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number |
@@ -180,7 +191,7 @@ nodes
| tst.ts:16:53:16:57 | [BinaryExpr] x + y | semmle.label | [BinaryExpr] x + y |
| tst.ts:16:57:16:57 | [VarRef] y | semmle.label | [VarRef] y |
| tst.ts:18:1:18:40 | [FunctionDeclStmt] functio ... + y; } | semmle.label | [FunctionDeclStmt] functio ... + y; } |
-| tst.ts:18:1:18:40 | [FunctionDeclStmt] functio ... + y; } | semmle.order | 26 |
+| tst.ts:18:1:18:40 | [FunctionDeclStmt] functio ... + y; } | semmle.order | 27 |
| tst.ts:18:10:18:16 | [VarDecl] untyped | semmle.label | [VarDecl] untyped |
| tst.ts:18:18:18:18 | [SimpleParameter] x | semmle.label | [SimpleParameter] x |
| tst.ts:18:21:18:21 | [SimpleParameter] y | semmle.label | [SimpleParameter] y |
@@ -190,7 +201,7 @@ nodes
| tst.ts:18:33:18:37 | [BinaryExpr] x + y | semmle.label | [BinaryExpr] x + y |
| tst.ts:18:37:18:37 | [VarRef] y | semmle.label | [VarRef] y |
| tst.ts:20:1:20:53 | [FunctionDeclStmt] functio ... + y; } | semmle.label | [FunctionDeclStmt] functio ... + y; } |
-| tst.ts:20:1:20:53 | [FunctionDeclStmt] functio ... + y; } | semmle.order | 27 |
+| tst.ts:20:1:20:53 | [FunctionDeclStmt] functio ... + y; } | semmle.order | 28 |
| tst.ts:20:10:20:21 | [VarDecl] partialTyped | semmle.label | [VarDecl] partialTyped |
| tst.ts:20:23:20:23 | [SimpleParameter] x | semmle.label | [SimpleParameter] x |
| tst.ts:20:26:20:26 | [SimpleParameter] y | semmle.label | [SimpleParameter] y |
@@ -201,7 +212,7 @@ nodes
| tst.ts:20:46:20:50 | [BinaryExpr] x + y | semmle.label | [BinaryExpr] x + y |
| tst.ts:20:50:20:50 | [VarRef] y | semmle.label | [VarRef] y |
| tst.ts:22:1:22:34 | [ForOfStmt] for (le ... 2]) {} | semmle.label | [ForOfStmt] for (le ... 2]) {} |
-| tst.ts:22:1:22:34 | [ForOfStmt] for (le ... 2]) {} | semmle.order | 28 |
+| tst.ts:22:1:22:34 | [ForOfStmt] for (le ... 2]) {} | semmle.order | 29 |
| tst.ts:22:6:22:20 | [DeclStmt] let numFromLoop = ... | semmle.label | [DeclStmt] let numFromLoop = ... |
| tst.ts:22:10:22:20 | [VarDecl] numFromLoop | semmle.label | [VarDecl] numFromLoop |
| tst.ts:22:10:22:20 | [VariableDeclarator] numFromLoop | semmle.label | [VariableDeclarator] numFromLoop |
@@ -210,54 +221,54 @@ nodes
| tst.ts:22:29:22:29 | [Literal] 2 | semmle.label | [Literal] 2 |
| tst.ts:22:33:22:34 | [BlockStmt] {} | semmle.label | [BlockStmt] {} |
| tst.ts:24:1:24:20 | [DeclStmt] let array = ... | semmle.label | [DeclStmt] let array = ... |
-| tst.ts:24:1:24:20 | [DeclStmt] let array = ... | semmle.order | 29 |
+| tst.ts:24:1:24:20 | [DeclStmt] let array = ... | semmle.order | 30 |
| tst.ts:24:5:24:9 | [VarDecl] array | semmle.label | [VarDecl] array |
| tst.ts:24:5:24:19 | [VariableDeclarator] array: number[] | semmle.label | [VariableDeclarator] array: number[] |
| tst.ts:24:12:24:17 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number |
| tst.ts:24:12:24:19 | [ArrayTypeExpr] number[] | semmle.label | [ArrayTypeExpr] number[] |
| tst.ts:26:1:26:25 | [DeclStmt] let voidType = ... | semmle.label | [DeclStmt] let voidType = ... |
-| tst.ts:26:1:26:25 | [DeclStmt] let voidType = ... | semmle.order | 30 |
+| tst.ts:26:1:26:25 | [DeclStmt] let voidType = ... | semmle.order | 31 |
| tst.ts:26:5:26:12 | [VarDecl] voidType | semmle.label | [VarDecl] voidType |
| tst.ts:26:5:26:24 | [VariableDeclarator] voidType: () => void | semmle.label | [VariableDeclarator] voidType: () => void |
| tst.ts:26:15:26:24 | [FunctionExpr] () => void | semmle.label | [FunctionExpr] () => void |
| tst.ts:26:15:26:24 | [FunctionTypeExpr] () => void | semmle.label | [FunctionTypeExpr] () => void |
| tst.ts:26:21:26:24 | [KeywordTypeExpr] void | semmle.label | [KeywordTypeExpr] void |
| tst.ts:27:1:27:29 | [DeclStmt] let undefinedType = ... | semmle.label | [DeclStmt] let undefinedType = ... |
-| tst.ts:27:1:27:29 | [DeclStmt] let undefinedType = ... | semmle.order | 31 |
+| tst.ts:27:1:27:29 | [DeclStmt] let undefinedType = ... | semmle.order | 32 |
| tst.ts:27:5:27:17 | [VarDecl] undefinedType | semmle.label | [VarDecl] undefinedType |
| tst.ts:27:5:27:28 | [VariableDeclarator] undefin ... defined | semmle.label | [VariableDeclarator] undefin ... defined |
| tst.ts:27:20:27:28 | [KeywordTypeExpr] undefined | semmle.label | [KeywordTypeExpr] undefined |
| tst.ts:28:1:28:26 | [DeclStmt] let nullType = ... | semmle.label | [DeclStmt] let nullType = ... |
-| tst.ts:28:1:28:26 | [DeclStmt] let nullType = ... | semmle.order | 32 |
+| tst.ts:28:1:28:26 | [DeclStmt] let nullType = ... | semmle.order | 33 |
| tst.ts:28:5:28:12 | [VarDecl] nullType | semmle.label | [VarDecl] nullType |
| tst.ts:28:5:28:25 | [VariableDeclarator] nullTyp ... = null | semmle.label | [VariableDeclarator] nullTyp ... = null |
| tst.ts:28:15:28:18 | [KeywordTypeExpr] null | semmle.label | [KeywordTypeExpr] null |
| tst.ts:28:22:28:25 | [Literal] null | semmle.label | [Literal] null |
| tst.ts:29:1:29:27 | [DeclStmt] let neverType = ... | semmle.label | [DeclStmt] let neverType = ... |
-| tst.ts:29:1:29:27 | [DeclStmt] let neverType = ... | semmle.order | 33 |
+| tst.ts:29:1:29:27 | [DeclStmt] let neverType = ... | semmle.order | 34 |
| tst.ts:29:5:29:13 | [VarDecl] neverType | semmle.label | [VarDecl] neverType |
| tst.ts:29:5:29:26 | [VariableDeclarator] neverTy ... > never | semmle.label | [VariableDeclarator] neverTy ... > never |
| tst.ts:29:16:29:26 | [FunctionExpr] () => never | semmle.label | [FunctionExpr] () => never |
| tst.ts:29:16:29:26 | [FunctionTypeExpr] () => never | semmle.label | [FunctionTypeExpr] () => never |
| tst.ts:29:22:29:26 | [KeywordTypeExpr] never | semmle.label | [KeywordTypeExpr] never |
| tst.ts:30:1:30:23 | [DeclStmt] let symbolType = ... | semmle.label | [DeclStmt] let symbolType = ... |
-| tst.ts:30:1:30:23 | [DeclStmt] let symbolType = ... | semmle.order | 34 |
+| tst.ts:30:1:30:23 | [DeclStmt] let symbolType = ... | semmle.order | 35 |
| tst.ts:30:5:30:14 | [VarDecl] symbolType | semmle.label | [VarDecl] symbolType |
| tst.ts:30:5:30:22 | [VariableDeclarator] symbolType: symbol | semmle.label | [VariableDeclarator] symbolType: symbol |
| tst.ts:30:17:30:22 | [KeywordTypeExpr] symbol | semmle.label | [KeywordTypeExpr] symbol |
| tst.ts:31:1:31:45 | [DeclStmt] const uniqueSymbolType = ... | semmle.label | [DeclStmt] const uniqueSymbolType = ... |
-| tst.ts:31:1:31:45 | [DeclStmt] const uniqueSymbolType = ... | semmle.order | 35 |
+| tst.ts:31:1:31:45 | [DeclStmt] const uniqueSymbolType = ... | semmle.order | 36 |
| tst.ts:31:7:31:22 | [VarDecl] uniqueSymbolType | semmle.label | [VarDecl] uniqueSymbolType |
| tst.ts:31:7:31:44 | [VariableDeclarator] uniqueS ... = null | semmle.label | [VariableDeclarator] uniqueS ... = null |
| tst.ts:31:25:31:37 | [KeywordTypeExpr] unique symbol | semmle.label | [KeywordTypeExpr] unique symbol |
| tst.ts:31:41:31:44 | [Literal] null | semmle.label | [Literal] null |
| tst.ts:32:1:32:23 | [DeclStmt] let objectType = ... | semmle.label | [DeclStmt] let objectType = ... |
-| tst.ts:32:1:32:23 | [DeclStmt] let objectType = ... | semmle.order | 36 |
+| tst.ts:32:1:32:23 | [DeclStmt] let objectType = ... | semmle.order | 37 |
| tst.ts:32:5:32:14 | [VarDecl] objectType | semmle.label | [VarDecl] objectType |
| tst.ts:32:5:32:22 | [VariableDeclarator] objectType: object | semmle.label | [VariableDeclarator] objectType: object |
| tst.ts:32:17:32:22 | [KeywordTypeExpr] object | semmle.label | [KeywordTypeExpr] object |
| tst.ts:33:1:33:39 | [DeclStmt] let intersection = ... | semmle.label | [DeclStmt] let intersection = ... |
-| tst.ts:33:1:33:39 | [DeclStmt] let intersection = ... | semmle.order | 37 |
+| tst.ts:33:1:33:39 | [DeclStmt] let intersection = ... | semmle.order | 38 |
| tst.ts:33:5:33:16 | [VarDecl] intersection | semmle.label | [VarDecl] intersection |
| tst.ts:33:5:33:38 | [VariableDeclarator] interse ... string} | semmle.label | [VariableDeclarator] interse ... string} |
| tst.ts:33:19:33:24 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string |
@@ -267,14 +278,14 @@ nodes
| tst.ts:33:29:33:37 | [FieldDeclaration] x: string | semmle.label | [FieldDeclaration] x: string |
| tst.ts:33:32:33:37 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string |
| tst.ts:34:1:34:28 | [DeclStmt] let tuple = ... | semmle.label | [DeclStmt] let tuple = ... |
-| tst.ts:34:1:34:28 | [DeclStmt] let tuple = ... | semmle.order | 38 |
+| tst.ts:34:1:34:28 | [DeclStmt] let tuple = ... | semmle.order | 39 |
| tst.ts:34:5:34:9 | [VarDecl] tuple | semmle.label | [VarDecl] tuple |
| tst.ts:34:5:34:27 | [VariableDeclarator] tuple: ... string] | semmle.label | [VariableDeclarator] tuple: ... string] |
| tst.ts:34:12:34:27 | [TupleTypeExpr] [number, string] | semmle.label | [TupleTypeExpr] [number, string] |
| tst.ts:34:13:34:18 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number |
| tst.ts:34:21:34:26 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string |
| tst.ts:36:1:36:56 | [DeclStmt] let tupleWithOptionalElement = ... | semmle.label | [DeclStmt] let tupleWithOptionalElement = ... |
-| tst.ts:36:1:36:56 | [DeclStmt] let tupleWithOptionalElement = ... | semmle.order | 39 |
+| tst.ts:36:1:36:56 | [DeclStmt] let tupleWithOptionalElement = ... | semmle.order | 40 |
| tst.ts:36:5:36:28 | [VarDecl] tupleWithOptionalElement | semmle.label | [VarDecl] tupleWithOptionalElement |
| tst.ts:36:5:36:55 | [VariableDeclarator] tupleWi ... umber?] | semmle.label | [VariableDeclarator] tupleWi ... umber?] |
| tst.ts:36:31:36:55 | [TupleTypeExpr] [number ... umber?] | semmle.label | [TupleTypeExpr] [number ... umber?] |
@@ -283,12 +294,12 @@ nodes
| tst.ts:36:48:36:53 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number |
| tst.ts:36:48:36:54 | [OptionalTypeExpr] number? | semmle.label | [OptionalTypeExpr] number? |
| tst.ts:37:1:37:19 | [DeclStmt] let emptyTuple = ... | semmle.label | [DeclStmt] let emptyTuple = ... |
-| tst.ts:37:1:37:19 | [DeclStmt] let emptyTuple = ... | semmle.order | 40 |
+| tst.ts:37:1:37:19 | [DeclStmt] let emptyTuple = ... | semmle.order | 41 |
| tst.ts:37:5:37:14 | [VarDecl] emptyTuple | semmle.label | [VarDecl] emptyTuple |
| tst.ts:37:5:37:18 | [VariableDeclarator] emptyTuple: [] | semmle.label | [VariableDeclarator] emptyTuple: [] |
| tst.ts:37:17:37:18 | [TupleTypeExpr] [] | semmle.label | [TupleTypeExpr] [] |
| tst.ts:38:1:38:48 | [DeclStmt] let tupleWithRestElement = ... | semmle.label | [DeclStmt] let tupleWithRestElement = ... |
-| tst.ts:38:1:38:48 | [DeclStmt] let tupleWithRestElement = ... | semmle.order | 41 |
+| tst.ts:38:1:38:48 | [DeclStmt] let tupleWithRestElement = ... | semmle.order | 42 |
| tst.ts:38:5:38:24 | [VarDecl] tupleWithRestElement | semmle.label | [VarDecl] tupleWithRestElement |
| tst.ts:38:5:38:47 | [VariableDeclarator] tupleWi ... ring[]] | semmle.label | [VariableDeclarator] tupleWi ... ring[]] |
| tst.ts:38:27:38:47 | [TupleTypeExpr] [number ... ring[]] | semmle.label | [TupleTypeExpr] [number ... ring[]] |
@@ -297,7 +308,7 @@ nodes
| tst.ts:38:39:38:44 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string |
| tst.ts:38:39:38:46 | [ArrayTypeExpr] string[] | semmle.label | [ArrayTypeExpr] string[] |
| tst.ts:39:1:39:69 | [DeclStmt] let tupleWithOptionalAndRestElements = ... | semmle.label | [DeclStmt] let tupleWithOptionalAndRestElements = ... |
-| tst.ts:39:1:39:69 | [DeclStmt] let tupleWithOptionalAndRestElements = ... | semmle.order | 42 |
+| tst.ts:39:1:39:69 | [DeclStmt] let tupleWithOptionalAndRestElements = ... | semmle.order | 43 |
| tst.ts:39:5:39:36 | [VarDecl] tupleWithOptionalAndRestElements | semmle.label | [VarDecl] tupleWithOptionalAndRestElements |
| tst.ts:39:5:39:68 | [VariableDeclarator] tupleWi ... mber[]] | semmle.label | [VariableDeclarator] tupleWi ... mber[]] |
| tst.ts:39:39:39:68 | [TupleTypeExpr] [number ... mber[]] | semmle.label | [TupleTypeExpr] [number ... mber[]] |
@@ -308,12 +319,12 @@ nodes
| tst.ts:39:60:39:65 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number |
| tst.ts:39:60:39:67 | [ArrayTypeExpr] number[] | semmle.label | [ArrayTypeExpr] number[] |
| tst.ts:40:1:40:25 | [DeclStmt] let unknownType = ... | semmle.label | [DeclStmt] let unknownType = ... |
-| tst.ts:40:1:40:25 | [DeclStmt] let unknownType = ... | semmle.order | 43 |
+| tst.ts:40:1:40:25 | [DeclStmt] let unknownType = ... | semmle.order | 44 |
| tst.ts:40:5:40:15 | [VarDecl] unknownType | semmle.label | [VarDecl] unknownType |
| tst.ts:40:5:40:24 | [VariableDeclarator] unknownType: unknown | semmle.label | [VariableDeclarator] unknownType: unknown |
| tst.ts:40:18:40:24 | [KeywordTypeExpr] unknown | semmle.label | [KeywordTypeExpr] unknown |
| tst.ts:42:1:42:40 | [DeclStmt] let constArrayLiteral = ... | semmle.label | [DeclStmt] let constArrayLiteral = ... |
-| tst.ts:42:1:42:40 | [DeclStmt] let constArrayLiteral = ... | semmle.order | 44 |
+| tst.ts:42:1:42:40 | [DeclStmt] let constArrayLiteral = ... | semmle.order | 45 |
| tst.ts:42:5:42:21 | [VarDecl] constArrayLiteral | semmle.label | [VarDecl] constArrayLiteral |
| tst.ts:42:5:42:39 | [VariableDeclarator] constAr ... s const | semmle.label | [VariableDeclarator] constAr ... s const |
| tst.ts:42:25:42:30 | [ArrayExpr] [1, 2] | semmle.label | [ArrayExpr] [1, 2] |
@@ -322,7 +333,7 @@ nodes
| tst.ts:42:29:42:29 | [Literal] 2 | semmle.label | [Literal] 2 |
| tst.ts:42:35:42:39 | [KeywordTypeExpr] const | semmle.label | [KeywordTypeExpr] const |
| tst.ts:43:1:43:49 | [DeclStmt] let constObjectLiteral = ... | semmle.label | [DeclStmt] let constObjectLiteral = ... |
-| tst.ts:43:1:43:49 | [DeclStmt] let constObjectLiteral = ... | semmle.order | 45 |
+| tst.ts:43:1:43:49 | [DeclStmt] let constObjectLiteral = ... | semmle.order | 46 |
| tst.ts:43:5:43:22 | [VarDecl] constObjectLiteral | semmle.label | [VarDecl] constObjectLiteral |
| tst.ts:43:5:43:48 | [VariableDeclarator] constOb ... s const | semmle.label | [VariableDeclarator] constOb ... s const |
| tst.ts:43:26:43:39 | [ObjectExpr] {foo: ...} | semmle.label | [ObjectExpr] {foo: ...} |
@@ -332,7 +343,7 @@ nodes
| tst.ts:43:33:43:37 | [Literal] "foo" | semmle.label | [Literal] "foo" |
| tst.ts:43:44:43:48 | [KeywordTypeExpr] const | semmle.label | [KeywordTypeExpr] const |
| tst.ts:46:1:51:1 | [TryStmt] try { } ... ; } } | semmle.label | [TryStmt] try { } ... ; } } |
-| tst.ts:46:1:51:1 | [TryStmt] try { } ... ; } } | semmle.order | 46 |
+| tst.ts:46:1:51:1 | [TryStmt] try { } ... ; } } | semmle.order | 47 |
| tst.ts:46:5:46:7 | [BlockStmt] { } | semmle.label | [BlockStmt] { } |
| tst.ts:47:1:51:1 | [CatchClause] catch ( ... ; } } | semmle.label | [CatchClause] catch ( ... ; } } |
| tst.ts:47:8:47:8 | [SimpleParameter] e | semmle.label | [SimpleParameter] e |
@@ -349,21 +360,21 @@ nodes
| tst.ts:49:15:49:20 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string |
| tst.ts:49:24:49:24 | [VarRef] e | semmle.label | [VarRef] e |
| tst.ts:54:1:56:1 | [InterfaceDeclaration,TypeDefinition] interfa ... mber; } | semmle.label | [InterfaceDeclaration,TypeDefinition] interfa ... mber; } |
-| tst.ts:54:1:56:1 | [InterfaceDeclaration,TypeDefinition] interfa ... mber; } | semmle.order | 47 |
+| tst.ts:54:1:56:1 | [InterfaceDeclaration,TypeDefinition] interfa ... mber; } | semmle.order | 48 |
| tst.ts:54:11:54:26 | [Identifier] NonAbstractDummy | semmle.label | [Identifier] NonAbstractDummy |
| tst.ts:55:3:55:9 | [Label] getArea | semmle.label | [Label] getArea |
| tst.ts:55:3:55:20 | [FunctionExpr] getArea(): number; | semmle.label | [FunctionExpr] getArea(): number; |
| tst.ts:55:3:55:20 | [MethodSignature] getArea(): number; | semmle.label | [MethodSignature] getArea(): number; |
| tst.ts:55:14:55:19 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number |
| tst.ts:58:1:60:1 | [InterfaceDeclaration,TypeDefinition] interfa ... mber; } | semmle.label | [InterfaceDeclaration,TypeDefinition] interfa ... mber; } |
-| tst.ts:58:1:60:1 | [InterfaceDeclaration,TypeDefinition] interfa ... mber; } | semmle.order | 48 |
+| tst.ts:58:1:60:1 | [InterfaceDeclaration,TypeDefinition] interfa ... mber; } | semmle.order | 49 |
| tst.ts:58:11:58:17 | [Identifier] HasArea | semmle.label | [Identifier] HasArea |
| tst.ts:59:3:59:9 | [Label] getArea | semmle.label | [Label] getArea |
| tst.ts:59:3:59:20 | [FunctionExpr] getArea(): number; | semmle.label | [FunctionExpr] getArea(): number; |
| tst.ts:59:3:59:20 | [MethodSignature] getArea(): number; | semmle.label | [MethodSignature] getArea(): number; |
| tst.ts:59:14:59:19 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number |
| tst.ts:63:1:63:45 | [DeclStmt] let Ctor = ... | semmle.label | [DeclStmt] let Ctor = ... |
-| tst.ts:63:1:63:45 | [DeclStmt] let Ctor = ... | semmle.order | 49 |
+| tst.ts:63:1:63:45 | [DeclStmt] let Ctor = ... | semmle.order | 50 |
| tst.ts:63:5:63:8 | [VarDecl] Ctor | semmle.label | [VarDecl] Ctor |
| tst.ts:63:5:63:44 | [VariableDeclarator] Ctor: a ... = Shape | semmle.label | [VariableDeclarator] Ctor: a ... = Shape |
| tst.ts:63:11:63:36 | [FunctionExpr] abstrac ... HasArea | semmle.label | [FunctionExpr] abstrac ... HasArea |
@@ -371,7 +382,7 @@ nodes
| tst.ts:63:30:63:36 | [LocalTypeAccess] HasArea | semmle.label | [LocalTypeAccess] HasArea |
| tst.ts:63:40:63:44 | [VarRef] Shape | semmle.label | [VarRef] Shape |
| tst.ts:65:1:65:54 | [TypeAliasDeclaration,TypeDefinition] type My ... true}; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type My ... true}; |
-| tst.ts:65:1:65:54 | [TypeAliasDeclaration,TypeDefinition] type My ... true}; | semmle.order | 50 |
+| tst.ts:65:1:65:54 | [TypeAliasDeclaration,TypeDefinition] type My ... true}; | semmle.order | 51 |
| tst.ts:65:6:65:12 | [Identifier] MyUnion | semmle.label | [Identifier] MyUnion |
| tst.ts:65:16:65:30 | [InterfaceTypeExpr] {myUnion: true} | semmle.label | [InterfaceTypeExpr] {myUnion: true} |
| tst.ts:65:16:65:53 | [UnionTypeExpr] {myUnio ... : true} | semmle.label | [UnionTypeExpr] {myUnio ... : true} |
@@ -383,7 +394,7 @@ nodes
| tst.ts:65:35:65:52 | [FieldDeclaration] stillMyUnion: true | semmle.label | [FieldDeclaration] stillMyUnion: true |
| tst.ts:65:49:65:52 | [LiteralTypeExpr] true | semmle.label | [LiteralTypeExpr] true |
| tst.ts:66:1:66:38 | [DeclStmt] let union1 = ... | semmle.label | [DeclStmt] let union1 = ... |
-| tst.ts:66:1:66:38 | [DeclStmt] let union1 = ... | semmle.order | 51 |
+| tst.ts:66:1:66:38 | [DeclStmt] let union1 = ... | semmle.order | 52 |
| tst.ts:66:5:66:10 | [VarDecl] union1 | semmle.label | [VarDecl] union1 |
| tst.ts:66:5:66:37 | [VariableDeclarator] union1: ... : true} | semmle.label | [VariableDeclarator] union1: ... : true} |
| tst.ts:66:13:66:19 | [LocalTypeAccess] MyUnion | semmle.label | [LocalTypeAccess] MyUnion |
@@ -392,7 +403,7 @@ nodes
| tst.ts:66:24:66:36 | [Property] myUnion: true | semmle.label | [Property] myUnion: true |
| tst.ts:66:33:66:36 | [Literal] true | semmle.label | [Literal] true |
| tst.ts:68:1:68:49 | [TypeAliasDeclaration,TypeDefinition] type My ... true}; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type My ... true}; |
-| tst.ts:68:1:68:49 | [TypeAliasDeclaration,TypeDefinition] type My ... true}; | semmle.order | 52 |
+| tst.ts:68:1:68:49 | [TypeAliasDeclaration,TypeDefinition] type My ... true}; | semmle.order | 53 |
| tst.ts:68:6:68:13 | [Identifier] MyUnion2 | semmle.label | [Identifier] MyUnion2 |
| tst.ts:68:17:68:23 | [LocalTypeAccess] MyUnion | semmle.label | [LocalTypeAccess] MyUnion |
| tst.ts:68:17:68:48 | [UnionTypeExpr] MyUnion ... : true} | semmle.label | [UnionTypeExpr] MyUnion ... : true} |
@@ -401,7 +412,7 @@ nodes
| tst.ts:68:28:68:47 | [FieldDeclaration] yetAnotherType: true | semmle.label | [FieldDeclaration] yetAnotherType: true |
| tst.ts:68:44:68:47 | [LiteralTypeExpr] true | semmle.label | [LiteralTypeExpr] true |
| tst.ts:69:1:69:46 | [DeclStmt] let union2 = ... | semmle.label | [DeclStmt] let union2 = ... |
-| tst.ts:69:1:69:46 | [DeclStmt] let union2 = ... | semmle.order | 53 |
+| tst.ts:69:1:69:46 | [DeclStmt] let union2 = ... | semmle.order | 54 |
| tst.ts:69:5:69:10 | [VarDecl] union2 | semmle.label | [VarDecl] union2 |
| tst.ts:69:5:69:45 | [VariableDeclarator] union2: ... : true} | semmle.label | [VariableDeclarator] union2: ... : true} |
| tst.ts:69:13:69:20 | [LocalTypeAccess] MyUnion2 | semmle.label | [LocalTypeAccess] MyUnion2 |
@@ -410,16 +421,16 @@ nodes
| tst.ts:69:25:69:44 | [Property] yetAnotherType: true | semmle.label | [Property] yetAnotherType: true |
| tst.ts:69:41:69:44 | [Literal] true | semmle.label | [Literal] true |
| type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type B = boolean; |
-| type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | semmle.order | 54 |
+| type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | semmle.order | 55 |
| type_alias.ts:1:6:1:6 | [Identifier] B | semmle.label | [Identifier] B |
| type_alias.ts:1:10:1:16 | [KeywordTypeExpr] boolean | semmle.label | [KeywordTypeExpr] boolean |
| type_alias.ts:3:1:3:9 | [DeclStmt] var b = ... | semmle.label | [DeclStmt] var b = ... |
-| type_alias.ts:3:1:3:9 | [DeclStmt] var b = ... | semmle.order | 55 |
+| type_alias.ts:3:1:3:9 | [DeclStmt] var b = ... | semmle.order | 56 |
| type_alias.ts:3:5:3:5 | [VarDecl] b | semmle.label | [VarDecl] b |
| type_alias.ts:3:5:3:8 | [VariableDeclarator] b: B | semmle.label | [VariableDeclarator] b: B |
| type_alias.ts:3:8:3:8 | [LocalTypeAccess] B | semmle.label | [LocalTypeAccess] B |
| type_alias.ts:5:1:5:50 | [TypeAliasDeclaration,TypeDefinition] type Va ... ay>; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Va ... ay>; |
-| type_alias.ts:5:1:5:50 | [TypeAliasDeclaration,TypeDefinition] type Va ... ay>; | semmle.order | 56 |
+| type_alias.ts:5:1:5:50 | [TypeAliasDeclaration,TypeDefinition] type Va ... ay>; | semmle.order | 57 |
| type_alias.ts:5:6:5:17 | [Identifier] ValueOrArray | semmle.label | [Identifier] ValueOrArray |
| type_alias.ts:5:19:5:19 | [Identifier] T | semmle.label | [Identifier] T |
| type_alias.ts:5:19:5:19 | [TypeParameter] T | semmle.label | [TypeParameter] T |
@@ -431,14 +442,14 @@ nodes
| type_alias.ts:5:34:5:48 | [GenericTypeExpr] ValueOrArray | semmle.label | [GenericTypeExpr] ValueOrArray |
| type_alias.ts:5:47:5:47 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T |
| type_alias.ts:7:1:7:28 | [DeclStmt] var c = ... | semmle.label | [DeclStmt] var c = ... |
-| type_alias.ts:7:1:7:28 | [DeclStmt] var c = ... | semmle.order | 57 |
+| type_alias.ts:7:1:7:28 | [DeclStmt] var c = ... | semmle.order | 58 |
| type_alias.ts:7:5:7:5 | [VarDecl] c | semmle.label | [VarDecl] c |
| type_alias.ts:7:5:7:27 | [VariableDeclarator] c: Valu ... number> | semmle.label | [VariableDeclarator] c: Valu ... number> |
| type_alias.ts:7:8:7:19 | [LocalTypeAccess] ValueOrArray | semmle.label | [LocalTypeAccess] ValueOrArray |
| type_alias.ts:7:8:7:27 | [GenericTypeExpr] ValueOrArray | semmle.label | [GenericTypeExpr] ValueOrArray |
| type_alias.ts:7:21:7:26 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number |
| type_alias.ts:9:1:15:13 | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; |
-| type_alias.ts:9:1:15:13 | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; | semmle.order | 58 |
+| type_alias.ts:9:1:15:13 | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; | semmle.order | 59 |
| type_alias.ts:9:6:9:9 | [Identifier] Json | semmle.label | [Identifier] Json |
| type_alias.ts:10:5:15:12 | [UnionTypeExpr] \| strin ... Json[] | semmle.label | [UnionTypeExpr] \| strin ... Json[] |
| type_alias.ts:10:7:10:12 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string |
@@ -454,12 +465,12 @@ nodes
| type_alias.ts:15:7:15:10 | [LocalTypeAccess] Json | semmle.label | [LocalTypeAccess] Json |
| type_alias.ts:15:7:15:12 | [ArrayTypeExpr] Json[] | semmle.label | [ArrayTypeExpr] Json[] |
| type_alias.ts:17:1:17:15 | [DeclStmt] var json = ... | semmle.label | [DeclStmt] var json = ... |
-| type_alias.ts:17:1:17:15 | [DeclStmt] var json = ... | semmle.order | 59 |
+| type_alias.ts:17:1:17:15 | [DeclStmt] var json = ... | semmle.order | 60 |
| type_alias.ts:17:5:17:8 | [VarDecl] json | semmle.label | [VarDecl] json |
| type_alias.ts:17:5:17:14 | [VariableDeclarator] json: Json | semmle.label | [VariableDeclarator] json: Json |
| type_alias.ts:17:11:17:14 | [LocalTypeAccess] Json | semmle.label | [LocalTypeAccess] Json |
| type_alias.ts:19:1:21:57 | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; |
-| type_alias.ts:19:1:21:57 | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; | semmle.order | 60 |
+| type_alias.ts:19:1:21:57 | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; | semmle.order | 61 |
| type_alias.ts:19:6:19:16 | [Identifier] VirtualNode | semmle.label | [Identifier] VirtualNode |
| type_alias.ts:20:5:21:56 | [UnionTypeExpr] \| strin ... Node[]] | semmle.label | [UnionTypeExpr] \| strin ... Node[]] |
| type_alias.ts:20:7:20:12 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string |
@@ -475,7 +486,7 @@ nodes
| type_alias.ts:21:43:21:53 | [LocalTypeAccess] VirtualNode | semmle.label | [LocalTypeAccess] VirtualNode |
| type_alias.ts:21:43:21:55 | [ArrayTypeExpr] VirtualNode[] | semmle.label | [ArrayTypeExpr] VirtualNode[] |
| type_alias.ts:23:1:27:6 | [DeclStmt] const myNode = ... | semmle.label | [DeclStmt] const myNode = ... |
-| type_alias.ts:23:1:27:6 | [DeclStmt] const myNode = ... | semmle.order | 61 |
+| type_alias.ts:23:1:27:6 | [DeclStmt] const myNode = ... | semmle.order | 62 |
| type_alias.ts:23:7:23:12 | [VarDecl] myNode | semmle.label | [VarDecl] myNode |
| type_alias.ts:23:7:27:5 | [VariableDeclarator] myNode: ... ] ] | semmle.label | [VariableDeclarator] myNode: ... ] ] |
| type_alias.ts:23:15:23:25 | [LocalTypeAccess] VirtualNode | semmle.label | [LocalTypeAccess] VirtualNode |
@@ -500,12 +511,12 @@ nodes
| type_alias.ts:26:23:26:36 | [Literal] "second-child" | semmle.label | [Literal] "second-child" |
| type_alias.ts:26:41:26:62 | [Literal] "I'm the second child" | semmle.label | [Literal] "I'm the second child" |
| type_definition_objects.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.label | [ImportDeclaration] import ... dummy"; |
-| type_definition_objects.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 62 |
+| type_definition_objects.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 63 |
| type_definition_objects.ts:1:8:1:17 | [ImportSpecifier] * as dummy | semmle.label | [ImportSpecifier] * as dummy |
| type_definition_objects.ts:1:13:1:17 | [VarDecl] dummy | semmle.label | [VarDecl] dummy |
| type_definition_objects.ts:1:24:1:32 | [Literal] "./dummy" | semmle.label | [Literal] "./dummy" |
| type_definition_objects.ts:3:1:3:17 | [ExportDeclaration] export class C {} | semmle.label | [ExportDeclaration] export class C {} |
-| type_definition_objects.ts:3:1:3:17 | [ExportDeclaration] export class C {} | semmle.order | 63 |
+| type_definition_objects.ts:3:1:3:17 | [ExportDeclaration] export class C {} | semmle.order | 64 |
| type_definition_objects.ts:3:8:3:17 | [ClassDefinition,TypeDefinition] class C {} | semmle.label | [ClassDefinition,TypeDefinition] class C {} |
| type_definition_objects.ts:3:14:3:14 | [VarDecl] C | semmle.label | [VarDecl] C |
| type_definition_objects.ts:3:16:3:15 | [BlockStmt] {} | semmle.label | [BlockStmt] {} |
@@ -513,36 +524,36 @@ nodes
| type_definition_objects.ts:3:16:3:15 | [FunctionExpr] () {} | semmle.label | [FunctionExpr] () {} |
| type_definition_objects.ts:3:16:3:15 | [Label] constructor | semmle.label | [Label] constructor |
| type_definition_objects.ts:4:1:4:17 | [DeclStmt] let classObj = ... | semmle.label | [DeclStmt] let classObj = ... |
-| type_definition_objects.ts:4:1:4:17 | [DeclStmt] let classObj = ... | semmle.order | 64 |
+| type_definition_objects.ts:4:1:4:17 | [DeclStmt] let classObj = ... | semmle.order | 65 |
| type_definition_objects.ts:4:5:4:12 | [VarDecl] classObj | semmle.label | [VarDecl] classObj |
| type_definition_objects.ts:4:5:4:16 | [VariableDeclarator] classObj = C | semmle.label | [VariableDeclarator] classObj = C |
| type_definition_objects.ts:4:16:4:16 | [VarRef] C | semmle.label | [VarRef] C |
| type_definition_objects.ts:6:1:6:16 | [ExportDeclaration] export enum E {} | semmle.label | [ExportDeclaration] export enum E {} |
-| type_definition_objects.ts:6:1:6:16 | [ExportDeclaration] export enum E {} | semmle.order | 65 |
+| type_definition_objects.ts:6:1:6:16 | [ExportDeclaration] export enum E {} | semmle.order | 66 |
| type_definition_objects.ts:6:8:6:16 | [EnumDeclaration,TypeDefinition] enum E {} | semmle.label | [EnumDeclaration,TypeDefinition] enum E {} |
| type_definition_objects.ts:6:13:6:13 | [VarDecl] E | semmle.label | [VarDecl] E |
| type_definition_objects.ts:7:1:7:16 | [DeclStmt] let enumObj = ... | semmle.label | [DeclStmt] let enumObj = ... |
-| type_definition_objects.ts:7:1:7:16 | [DeclStmt] let enumObj = ... | semmle.order | 66 |
+| type_definition_objects.ts:7:1:7:16 | [DeclStmt] let enumObj = ... | semmle.order | 67 |
| type_definition_objects.ts:7:5:7:11 | [VarDecl] enumObj | semmle.label | [VarDecl] enumObj |
| type_definition_objects.ts:7:5:7:15 | [VariableDeclarator] enumObj = E | semmle.label | [VariableDeclarator] enumObj = E |
| type_definition_objects.ts:7:15:7:15 | [VarRef] E | semmle.label | [VarRef] E |
| type_definition_objects.ts:9:1:9:22 | [ExportDeclaration] export ... e N {;} | semmle.label | [ExportDeclaration] export ... e N {;} |
-| type_definition_objects.ts:9:1:9:22 | [ExportDeclaration] export ... e N {;} | semmle.order | 67 |
+| type_definition_objects.ts:9:1:9:22 | [ExportDeclaration] export ... e N {;} | semmle.order | 68 |
| type_definition_objects.ts:9:8:9:22 | [NamespaceDeclaration] namespace N {;} | semmle.label | [NamespaceDeclaration] namespace N {;} |
| type_definition_objects.ts:9:18:9:18 | [VarDecl] N | semmle.label | [VarDecl] N |
| type_definition_objects.ts:9:21:9:21 | [EmptyStmt] ; | semmle.label | [EmptyStmt] ; |
| type_definition_objects.ts:10:1:10:21 | [DeclStmt] let namespaceObj = ... | semmle.label | [DeclStmt] let namespaceObj = ... |
-| type_definition_objects.ts:10:1:10:21 | [DeclStmt] let namespaceObj = ... | semmle.order | 68 |
+| type_definition_objects.ts:10:1:10:21 | [DeclStmt] let namespaceObj = ... | semmle.order | 69 |
| type_definition_objects.ts:10:5:10:16 | [VarDecl] namespaceObj | semmle.label | [VarDecl] namespaceObj |
| type_definition_objects.ts:10:5:10:20 | [VariableDeclarator] namespaceObj = N | semmle.label | [VariableDeclarator] namespaceObj = N |
| type_definition_objects.ts:10:20:10:20 | [VarRef] N | semmle.label | [VarRef] N |
| type_definitions.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.label | [ImportDeclaration] import ... dummy"; |
-| type_definitions.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 69 |
+| type_definitions.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 70 |
| type_definitions.ts:1:8:1:17 | [ImportSpecifier] * as dummy | semmle.label | [ImportSpecifier] * as dummy |
| type_definitions.ts:1:13:1:17 | [VarDecl] dummy | semmle.label | [VarDecl] dummy |
| type_definitions.ts:1:24:1:32 | [Literal] "./dummy" | semmle.label | [Literal] "./dummy" |
| type_definitions.ts:3:1:5:1 | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } | semmle.label | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } |
-| type_definitions.ts:3:1:5:1 | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } | semmle.order | 70 |
+| type_definitions.ts:3:1:5:1 | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } | semmle.order | 71 |
| type_definitions.ts:3:11:3:11 | [Identifier] I | semmle.label | [Identifier] I |
| type_definitions.ts:3:13:3:13 | [Identifier] S | semmle.label | [Identifier] S |
| type_definitions.ts:3:13:3:13 | [TypeParameter] S | semmle.label | [TypeParameter] S |
@@ -550,14 +561,14 @@ nodes
| type_definitions.ts:4:3:4:7 | [FieldDeclaration] x: S; | semmle.label | [FieldDeclaration] x: S; |
| type_definitions.ts:4:6:4:6 | [LocalTypeAccess] S | semmle.label | [LocalTypeAccess] S |
| type_definitions.ts:6:1:6:16 | [DeclStmt] let i = ... | semmle.label | [DeclStmt] let i = ... |
-| type_definitions.ts:6:1:6:16 | [DeclStmt] let i = ... | semmle.order | 71 |
+| type_definitions.ts:6:1:6:16 | [DeclStmt] let i = ... | semmle.order | 72 |
| type_definitions.ts:6:5:6:5 | [VarDecl] i | semmle.label | [VarDecl] i |
| type_definitions.ts:6:5:6:16 | [VariableDeclarator] i: I | semmle.label | [VariableDeclarator] i: I |
| type_definitions.ts:6:8:6:8 | [LocalTypeAccess] I | semmle.label | [LocalTypeAccess] I |
| type_definitions.ts:6:8:6:16 | [GenericTypeExpr] I | semmle.label | [GenericTypeExpr] I |
| type_definitions.ts:6:10:6:15 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number |
| type_definitions.ts:8:1:10:1 | [ClassDefinition,TypeDefinition] class C ... x: T } | semmle.label | [ClassDefinition,TypeDefinition] class C ... x: T } |
-| type_definitions.ts:8:1:10:1 | [ClassDefinition,TypeDefinition] class C ... x: T } | semmle.order | 72 |
+| type_definitions.ts:8:1:10:1 | [ClassDefinition,TypeDefinition] class C ... x: T } | semmle.order | 73 |
| type_definitions.ts:8:7:8:7 | [VarDecl] C | semmle.label | [VarDecl] C |
| type_definitions.ts:8:8:8:7 | [BlockStmt] {} | semmle.label | [BlockStmt] {} |
| type_definitions.ts:8:8:8:7 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | semmle.label | [ClassInitializedMember,ConstructorDefinition] constructor() {} |
@@ -569,14 +580,14 @@ nodes
| type_definitions.ts:9:3:9:6 | [FieldDeclaration] x: T | semmle.label | [FieldDeclaration] x: T |
| type_definitions.ts:9:6:9:6 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T |
| type_definitions.ts:11:1:11:17 | [DeclStmt] let c = ... | semmle.label | [DeclStmt] let c = ... |
-| type_definitions.ts:11:1:11:17 | [DeclStmt] let c = ... | semmle.order | 73 |
+| type_definitions.ts:11:1:11:17 | [DeclStmt] let c = ... | semmle.order | 74 |
| type_definitions.ts:11:5:11:5 | [VarDecl] c | semmle.label | [VarDecl] c |
| type_definitions.ts:11:5:11:16 | [VariableDeclarator] c: C | semmle.label | [VariableDeclarator] c: C |
| type_definitions.ts:11:8:11:8 | [LocalTypeAccess] C | semmle.label | [LocalTypeAccess] C |
| type_definitions.ts:11:8:11:16 | [GenericTypeExpr] C | semmle.label | [GenericTypeExpr] C |
| type_definitions.ts:11:10:11:15 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number |
| type_definitions.ts:13:1:15:1 | [EnumDeclaration,TypeDefinition] enum Co ... blue } | semmle.label | [EnumDeclaration,TypeDefinition] enum Co ... blue } |
-| type_definitions.ts:13:1:15:1 | [EnumDeclaration,TypeDefinition] enum Co ... blue } | semmle.order | 74 |
+| type_definitions.ts:13:1:15:1 | [EnumDeclaration,TypeDefinition] enum Co ... blue } | semmle.order | 75 |
| type_definitions.ts:13:6:13:10 | [VarDecl] Color | semmle.label | [VarDecl] Color |
| type_definitions.ts:14:3:14:5 | [EnumMember,TypeDefinition] red | semmle.label | [EnumMember,TypeDefinition] red |
| type_definitions.ts:14:3:14:5 | [VarDecl] red | semmle.label | [VarDecl] red |
@@ -585,29 +596,29 @@ nodes
| type_definitions.ts:14:15:14:18 | [EnumMember,TypeDefinition] blue | semmle.label | [EnumMember,TypeDefinition] blue |
| type_definitions.ts:14:15:14:18 | [VarDecl] blue | semmle.label | [VarDecl] blue |
| type_definitions.ts:16:1:16:17 | [DeclStmt] let color = ... | semmle.label | [DeclStmt] let color = ... |
-| type_definitions.ts:16:1:16:17 | [DeclStmt] let color = ... | semmle.order | 75 |
+| type_definitions.ts:16:1:16:17 | [DeclStmt] let color = ... | semmle.order | 76 |
| type_definitions.ts:16:5:16:9 | [VarDecl] color | semmle.label | [VarDecl] color |
| type_definitions.ts:16:5:16:16 | [VariableDeclarator] color: Color | semmle.label | [VariableDeclarator] color: Color |
| type_definitions.ts:16:12:16:16 | [LocalTypeAccess] Color | semmle.label | [LocalTypeAccess] Color |
| type_definitions.ts:18:1:18:33 | [EnumDeclaration,TypeDefinition] enum En ... ember } | semmle.label | [EnumDeclaration,TypeDefinition] enum En ... ember } |
-| type_definitions.ts:18:1:18:33 | [EnumDeclaration,TypeDefinition] enum En ... ember } | semmle.order | 76 |
+| type_definitions.ts:18:1:18:33 | [EnumDeclaration,TypeDefinition] enum En ... ember } | semmle.order | 77 |
| type_definitions.ts:18:6:18:22 | [VarDecl] EnumWithOneMember | semmle.label | [VarDecl] EnumWithOneMember |
| type_definitions.ts:18:26:18:31 | [EnumMember,TypeDefinition] member | semmle.label | [EnumMember,TypeDefinition] member |
| type_definitions.ts:18:26:18:31 | [VarDecl] member | semmle.label | [VarDecl] member |
| type_definitions.ts:19:1:19:25 | [DeclStmt] let e = ... | semmle.label | [DeclStmt] let e = ... |
-| type_definitions.ts:19:1:19:25 | [DeclStmt] let e = ... | semmle.order | 77 |
+| type_definitions.ts:19:1:19:25 | [DeclStmt] let e = ... | semmle.order | 78 |
| type_definitions.ts:19:5:19:5 | [VarDecl] e | semmle.label | [VarDecl] e |
| type_definitions.ts:19:5:19:24 | [VariableDeclarator] e: EnumWithOneMember | semmle.label | [VariableDeclarator] e: EnumWithOneMember |
| type_definitions.ts:19:8:19:24 | [LocalTypeAccess] EnumWithOneMember | semmle.label | [LocalTypeAccess] EnumWithOneMember |
| type_definitions.ts:21:1:21:20 | [TypeAliasDeclaration,TypeDefinition] type Alias = T[]; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Alias = T[]; |
-| type_definitions.ts:21:1:21:20 | [TypeAliasDeclaration,TypeDefinition] type Alias = T[]; | semmle.order | 78 |
+| type_definitions.ts:21:1:21:20 | [TypeAliasDeclaration,TypeDefinition] type Alias = T[]; | semmle.order | 79 |
| type_definitions.ts:21:6:21:10 | [Identifier] Alias | semmle.label | [Identifier] Alias |
| type_definitions.ts:21:12:21:12 | [Identifier] T | semmle.label | [Identifier] T |
| type_definitions.ts:21:12:21:12 | [TypeParameter] T | semmle.label | [TypeParameter] T |
| type_definitions.ts:21:17:21:17 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T |
| type_definitions.ts:21:17:21:19 | [ArrayTypeExpr] T[] | semmle.label | [ArrayTypeExpr] T[] |
| type_definitions.ts:22:1:22:39 | [DeclStmt] let aliasForNumberArray = ... | semmle.label | [DeclStmt] let aliasForNumberArray = ... |
-| type_definitions.ts:22:1:22:39 | [DeclStmt] let aliasForNumberArray = ... | semmle.order | 79 |
+| type_definitions.ts:22:1:22:39 | [DeclStmt] let aliasForNumberArray = ... | semmle.order | 80 |
| type_definitions.ts:22:5:22:23 | [VarDecl] aliasForNumberArray | semmle.label | [VarDecl] aliasForNumberArray |
| type_definitions.ts:22:5:22:38 | [VariableDeclarator] aliasFo ... number> | semmle.label | [VariableDeclarator] aliasFo ... number> |
| type_definitions.ts:22:26:22:30 | [LocalTypeAccess] Alias | semmle.label | [LocalTypeAccess] Alias |
@@ -716,6 +727,24 @@ edges
| dummy.ts:2:12:2:16 | [VariableDeclarator] x = 5 | dummy.ts:2:12:2:12 | [VarDecl] x | semmle.order | 1 |
| dummy.ts:2:12:2:16 | [VariableDeclarator] x = 5 | dummy.ts:2:16:2:16 | [Literal] 5 | semmle.label | 2 |
| dummy.ts:2:12:2:16 | [VariableDeclarator] x = 5 | dummy.ts:2:16:2:16 | [Literal] 5 | semmle.order | 2 |
+| dummy.ts:4:1:4:24 | [ExportDeclaration] export ... /ab+c/; | dummy.ts:4:8:4:24 | [DeclStmt] let reg = ... | semmle.label | 1 |
+| dummy.ts:4:1:4:24 | [ExportDeclaration] export ... /ab+c/; | dummy.ts:4:8:4:24 | [DeclStmt] let reg = ... | semmle.order | 1 |
+| dummy.ts:4:8:4:24 | [DeclStmt] let reg = ... | dummy.ts:4:12:4:23 | [VariableDeclarator] reg = /ab+c/ | semmle.label | 1 |
+| dummy.ts:4:8:4:24 | [DeclStmt] let reg = ... | dummy.ts:4:12:4:23 | [VariableDeclarator] reg = /ab+c/ | semmle.order | 1 |
+| dummy.ts:4:12:4:23 | [VariableDeclarator] reg = /ab+c/ | dummy.ts:4:12:4:14 | [VarDecl] reg | semmle.label | 1 |
+| dummy.ts:4:12:4:23 | [VariableDeclarator] reg = /ab+c/ | dummy.ts:4:12:4:14 | [VarDecl] reg | semmle.order | 1 |
+| dummy.ts:4:12:4:23 | [VariableDeclarator] reg = /ab+c/ | dummy.ts:4:18:4:23 | [RegExpLiteral] /ab+c/ | semmle.label | 2 |
+| dummy.ts:4:12:4:23 | [VariableDeclarator] reg = /ab+c/ | dummy.ts:4:18:4:23 | [RegExpLiteral] /ab+c/ | semmle.order | 2 |
+| dummy.ts:4:18:4:23 | [RegExpLiteral] /ab+c/ | dummy.ts:4:19:4:22 | [RegExpSequence] ab+c | semmle.label | 0 |
+| dummy.ts:4:18:4:23 | [RegExpLiteral] /ab+c/ | dummy.ts:4:19:4:22 | [RegExpSequence] ab+c | semmle.order | 0 |
+| dummy.ts:4:19:4:22 | [RegExpSequence] ab+c | dummy.ts:4:19:4:19 | [RegExpNormalConstant] a | semmle.label | 0 |
+| dummy.ts:4:19:4:22 | [RegExpSequence] ab+c | dummy.ts:4:19:4:19 | [RegExpNormalConstant] a | semmle.order | 0 |
+| dummy.ts:4:19:4:22 | [RegExpSequence] ab+c | dummy.ts:4:20:4:21 | [RegExpPlus] b+ | semmle.label | 1 |
+| dummy.ts:4:19:4:22 | [RegExpSequence] ab+c | dummy.ts:4:20:4:21 | [RegExpPlus] b+ | semmle.order | 1 |
+| dummy.ts:4:19:4:22 | [RegExpSequence] ab+c | dummy.ts:4:22:4:22 | [RegExpNormalConstant] c | semmle.label | 2 |
+| dummy.ts:4:19:4:22 | [RegExpSequence] ab+c | dummy.ts:4:22:4:22 | [RegExpNormalConstant] c | semmle.order | 2 |
+| dummy.ts:4:20:4:21 | [RegExpPlus] b+ | dummy.ts:4:20:4:20 | [RegExpNormalConstant] b | semmle.label | 0 |
+| dummy.ts:4:20:4:21 | [RegExpPlus] b+ | dummy.ts:4:20:4:20 | [RegExpNormalConstant] b | semmle.order | 0 |
| file://:0:0:0:0 | (Parameters) | tst.ts:14:17:14:17 | [SimpleParameter] x | semmle.label | 0 |
| file://:0:0:0:0 | (Parameters) | tst.ts:14:17:14:17 | [SimpleParameter] x | semmle.order | 0 |
| file://:0:0:0:0 | (Parameters) | tst.ts:14:28:14:28 | [SimpleParameter] y | semmle.label | 1 |
diff --git a/javascript/ql/test/library-tests/TypeScript/Types/tests.expected b/javascript/ql/test/library-tests/TypeScript/Types/tests.expected
index c9cad8a1443..7c8159a9b10 100644
--- a/javascript/ql/test/library-tests/TypeScript/Types/tests.expected
+++ b/javascript/ql/test/library-tests/TypeScript/Types/tests.expected
@@ -15,6 +15,8 @@ getExprType
| boolean-type.ts:15:5:15:12 | boolean6 | boolean |
| dummy.ts:2:12:2:12 | x | number |
| dummy.ts:2:16:2:16 | 5 | 5 |
+| dummy.ts:4:12:4:14 | reg | RegExp |
+| dummy.ts:4:18:4:23 | /ab+c/ | RegExp |
| middle-rest.ts:1:5:1:7 | foo | [boolean, ...string[], number] |
| middle-rest.ts:3:1:3:3 | foo | [boolean, ...string[], number] |
| middle-rest.ts:3:1:3:26 | foo = [ ... ", 123] | [true, string, number] |
diff --git a/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected b/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected
index e448b888e12..27a9fa10f72 100644
--- a/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected
+++ b/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected
@@ -87,6 +87,7 @@ test_ClientRequest
| tst.js:271:3:271:61 | proxy.w ... 080' }) |
| tst.js:274:1:283:2 | httpPro ... true\\n}) |
| tst.js:286:20:286:55 | new Web ... :8080') |
+| tst.js:296:5:299:6 | axios({ ... \\n }) |
test_getADataNode
| tst.js:53:5:53:23 | axios({data: data}) | tst.js:53:18:53:21 | data |
| tst.js:57:5:57:39 | axios.p ... data2}) | tst.js:57:19:57:23 | data1 |
@@ -227,6 +228,8 @@ test_getUrl
| tst.js:271:3:271:61 | proxy.w ... 080' }) | tst.js:271:33:271:58 | 'http:/ ... m:8080' |
| tst.js:274:1:283:2 | httpPro ... true\\n}) | tst.js:275:13:281:5 | {\\n ... ,\\n } |
| tst.js:286:20:286:55 | new Web ... :8080') | tst.js:286:34:286:54 | 'ws://l ... t:8080' |
+| tst.js:296:5:299:6 | axios({ ... \\n }) | tst.js:296:11:299:5 | {\\n ... ,\\n } |
+| tst.js:296:5:299:6 | axios({ ... \\n }) | tst.js:298:14:298:44 | "http:/ ... -axios" |
test_getAResponseDataNode
| tst.js:19:5:19:23 | requestPromise(url) | tst.js:19:5:19:23 | requestPromise(url) | text | true |
| tst.js:21:5:21:23 | superagent.get(url) | tst.js:21:5:21:23 | superagent.get(url) | stream | true |
@@ -294,3 +297,7 @@ test_getAResponseDataNode
| tst.js:235:5:237:6 | needle. ... \\n }) | tst.js:235:67:235:70 | resp | fetch.response | false |
| tst.js:235:5:237:6 | needle. ... \\n }) | tst.js:235:73:235:76 | body | json | false |
| tst.js:286:20:286:55 | new Web ... :8080') | tst.js:291:44:291:53 | event.data | json | false |
+| tst.js:296:5:299:6 | axios({ ... \\n }) | tst.js:296:5:299:6 | axios({ ... \\n }) | json | true |
+| tst.js:296:5:299:6 | axios({ ... \\n }) | tst.js:302:28:302:39 | err.response | json | false |
+| tst.js:296:5:299:6 | axios({ ... \\n }) | tst.js:303:26:303:37 | err.response | json | false |
+| tst.js:296:5:299:6 | axios({ ... \\n }) | tst.js:304:27:304:38 | err.response | json | false |
diff --git a/javascript/ql/test/library-tests/frameworks/ClientRequests/tst.js b/javascript/ql/test/library-tests/frameworks/ClientRequests/tst.js
index bc15565c072..40dcfc481f4 100644
--- a/javascript/ql/test/library-tests/frameworks/ClientRequests/tst.js
+++ b/javascript/ql/test/library-tests/frameworks/ClientRequests/tst.js
@@ -290,4 +290,18 @@ function webSocket() {
socket.addEventListener('message', function (event) {
console.log("Data from server: " + event.data);
});
+}
+
+function moreAxios() {
+ axios({
+ method: 'GET',
+ url: "http://example.org/more-axios",
+ }).then(
+ x => res.send(x.data),
+ (err) => {
+ const status = err.response.status;
+ const data = err.response.data;
+ const agent = err.response.headers.useragent;
+ }
+ );
}
\ No newline at end of file
diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected
index f8ceeb45b62..e8d093325ad 100644
--- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected
+++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected
@@ -174,6 +174,14 @@ nodes
| tst2.js:18:12:18:12 | p |
| tst2.js:21:14:21:14 | p |
| tst2.js:21:14:21:14 | p |
+| tst2.js:30:7:30:24 | p |
+| tst2.js:30:9:30:9 | p |
+| tst2.js:30:9:30:9 | p |
+| tst2.js:33:11:33:11 | p |
+| tst2.js:36:12:36:12 | p |
+| tst2.js:36:12:36:12 | p |
+| tst2.js:37:12:37:18 | other.p |
+| tst2.js:37:12:37:18 | other.p |
edges
| ReflectedXss.js:8:33:8:45 | req.params.id | ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id |
| ReflectedXss.js:8:33:8:45 | req.params.id | ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id |
@@ -318,6 +326,13 @@ edges
| tst2.js:14:7:14:24 | p | tst2.js:21:14:21:14 | p |
| tst2.js:14:9:14:9 | p | tst2.js:14:7:14:24 | p |
| tst2.js:14:9:14:9 | p | tst2.js:14:7:14:24 | p |
+| tst2.js:30:7:30:24 | p | tst2.js:33:11:33:11 | p |
+| tst2.js:30:7:30:24 | p | tst2.js:36:12:36:12 | p |
+| tst2.js:30:7:30:24 | p | tst2.js:36:12:36:12 | p |
+| tst2.js:30:9:30:9 | p | tst2.js:30:7:30:24 | p |
+| tst2.js:30:9:30:9 | p | tst2.js:30:7:30:24 | p |
+| tst2.js:33:11:33:11 | p | tst2.js:37:12:37:18 | other.p |
+| tst2.js:33:11:33:11 | p | tst2.js:37:12:37:18 | other.p |
#select
| ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | ReflectedXss.js:8:33:8:45 | req.params.id | ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:8:33:8:45 | req.params.id | user-provided value |
| ReflectedXss.js:17:12:17:39 | "Unknow ... rams.id | ReflectedXss.js:17:31:17:39 | params.id | ReflectedXss.js:17:12:17:39 | "Unknow ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:17:31:17:39 | params.id | user-provided value |
@@ -359,3 +374,5 @@ edges
| tst2.js:8:12:8:12 | r | tst2.js:6:12:6:15 | q: r | tst2.js:8:12:8:12 | r | Cross-site scripting vulnerability due to $@. | tst2.js:6:12:6:15 | q: r | user-provided value |
| tst2.js:18:12:18:12 | p | tst2.js:14:9:14:9 | p | tst2.js:18:12:18:12 | p | Cross-site scripting vulnerability due to $@. | tst2.js:14:9:14:9 | p | user-provided value |
| tst2.js:21:14:21:14 | p | tst2.js:14:9:14:9 | p | tst2.js:21:14:21:14 | p | Cross-site scripting vulnerability due to $@. | tst2.js:14:9:14:9 | p | user-provided value |
+| tst2.js:36:12:36:12 | p | tst2.js:30:9:30:9 | p | tst2.js:36:12:36:12 | p | Cross-site scripting vulnerability due to $@. | tst2.js:30:9:30:9 | p | user-provided value |
+| tst2.js:37:12:37:18 | other.p | tst2.js:30:9:30:9 | p | tst2.js:37:12:37:18 | other.p | Cross-site scripting vulnerability due to $@. | tst2.js:30:9:30:9 | p | user-provided value |
diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected
index 719a82171a8..8ddc55dde36 100644
--- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected
+++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected
@@ -37,3 +37,5 @@
| tst2.js:8:12:8:12 | r | Cross-site scripting vulnerability due to $@. | tst2.js:6:12:6:15 | q: r | user-provided value |
| tst2.js:18:12:18:12 | p | Cross-site scripting vulnerability due to $@. | tst2.js:14:9:14:9 | p | user-provided value |
| tst2.js:21:14:21:14 | p | Cross-site scripting vulnerability due to $@. | tst2.js:14:9:14:9 | p | user-provided value |
+| tst2.js:36:12:36:12 | p | Cross-site scripting vulnerability due to $@. | tst2.js:30:9:30:9 | p | user-provided value |
+| tst2.js:37:12:37:18 | other.p | Cross-site scripting vulnerability due to $@. | tst2.js:30:9:30:9 | p | user-provided value |
diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/tst2.js b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/tst2.js
index 521b6b20a7c..034b0791217 100644
--- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/tst2.js
+++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/tst2.js
@@ -22,3 +22,17 @@ app.get('/bar', function(req, res) {
else
res.send(p); // OK
});
+
+
+const clone = require('clone');
+
+app.get('/baz', function(req, res) {
+ let { p } = req.params;
+
+ var obj = {};
+ obj.p = p;
+ var other = clone(obj);
+
+ res.send(p); // NOT OK
+ res.send(other.p); // NOT OK
+});
\ No newline at end of file
diff --git a/javascript/ql/test/query-tests/Security/CWE-338/InsecureRandomness.expected b/javascript/ql/test/query-tests/Security/CWE-338/InsecureRandomness.expected
index e4ab385cc07..42da210c266 100644
--- a/javascript/ql/test/query-tests/Security/CWE-338/InsecureRandomness.expected
+++ b/javascript/ql/test/query-tests/Security/CWE-338/InsecureRandomness.expected
@@ -66,6 +66,32 @@ nodes
| tst.js:95:33:95:45 | Math.random() |
| tst.js:95:33:95:45 | Math.random() |
| tst.js:95:33:95:45 | Math.random() |
+| tst.js:115:16:115:56 | Math.fl ... 00_000) |
+| tst.js:115:16:115:56 | Math.fl ... 00_000) |
+| tst.js:115:27:115:39 | Math.random() |
+| tst.js:115:27:115:39 | Math.random() |
+| tst.js:115:27:115:55 | Math.ra ... 000_000 |
+| tst.js:116:22:116:62 | Math.fl ... 00_000) |
+| tst.js:116:22:116:62 | Math.fl ... 00_000) |
+| tst.js:116:33:116:45 | Math.random() |
+| tst.js:116:33:116:45 | Math.random() |
+| tst.js:116:33:116:61 | Math.ra ... 000_000 |
+| tst.js:117:15:117:55 | Math.fl ... 00_000) |
+| tst.js:117:15:117:55 | Math.fl ... 00_000) |
+| tst.js:117:26:117:38 | Math.random() |
+| tst.js:117:26:117:38 | Math.random() |
+| tst.js:117:26:117:54 | Math.ra ... 000_000 |
+| tst.js:118:23:118:63 | Math.fl ... 00_000) |
+| tst.js:118:23:118:63 | Math.fl ... 00_000) |
+| tst.js:118:34:118:46 | Math.random() |
+| tst.js:118:34:118:46 | Math.random() |
+| tst.js:118:34:118:62 | Math.ra ... 000_000 |
+| tst.js:120:16:120:28 | Math.random() |
+| tst.js:120:16:120:28 | Math.random() |
+| tst.js:120:16:120:28 | Math.random() |
+| tst.js:121:18:121:30 | Math.random() |
+| tst.js:121:18:121:30 | Math.random() |
+| tst.js:121:18:121:30 | Math.random() |
edges
| tst.js:2:20:2:32 | Math.random() | tst.js:2:20:2:32 | Math.random() |
| tst.js:6:31:6:43 | Math.random() | tst.js:6:20:6:43 | "prefix ... andom() |
@@ -114,6 +140,24 @@ edges
| tst.js:84:19:84:31 | Math.random() | tst.js:84:19:84:31 | Math.random() |
| tst.js:90:32:90:44 | Math.random() | tst.js:90:32:90:44 | Math.random() |
| tst.js:95:33:95:45 | Math.random() | tst.js:95:33:95:45 | Math.random() |
+| tst.js:115:27:115:39 | Math.random() | tst.js:115:27:115:55 | Math.ra ... 000_000 |
+| tst.js:115:27:115:39 | Math.random() | tst.js:115:27:115:55 | Math.ra ... 000_000 |
+| tst.js:115:27:115:55 | Math.ra ... 000_000 | tst.js:115:16:115:56 | Math.fl ... 00_000) |
+| tst.js:115:27:115:55 | Math.ra ... 000_000 | tst.js:115:16:115:56 | Math.fl ... 00_000) |
+| tst.js:116:33:116:45 | Math.random() | tst.js:116:33:116:61 | Math.ra ... 000_000 |
+| tst.js:116:33:116:45 | Math.random() | tst.js:116:33:116:61 | Math.ra ... 000_000 |
+| tst.js:116:33:116:61 | Math.ra ... 000_000 | tst.js:116:22:116:62 | Math.fl ... 00_000) |
+| tst.js:116:33:116:61 | Math.ra ... 000_000 | tst.js:116:22:116:62 | Math.fl ... 00_000) |
+| tst.js:117:26:117:38 | Math.random() | tst.js:117:26:117:54 | Math.ra ... 000_000 |
+| tst.js:117:26:117:38 | Math.random() | tst.js:117:26:117:54 | Math.ra ... 000_000 |
+| tst.js:117:26:117:54 | Math.ra ... 000_000 | tst.js:117:15:117:55 | Math.fl ... 00_000) |
+| tst.js:117:26:117:54 | Math.ra ... 000_000 | tst.js:117:15:117:55 | Math.fl ... 00_000) |
+| tst.js:118:34:118:46 | Math.random() | tst.js:118:34:118:62 | Math.ra ... 000_000 |
+| tst.js:118:34:118:46 | Math.random() | tst.js:118:34:118:62 | Math.ra ... 000_000 |
+| tst.js:118:34:118:62 | Math.ra ... 000_000 | tst.js:118:23:118:63 | Math.fl ... 00_000) |
+| tst.js:118:34:118:62 | Math.ra ... 000_000 | tst.js:118:23:118:63 | Math.fl ... 00_000) |
+| tst.js:120:16:120:28 | Math.random() | tst.js:120:16:120:28 | Math.random() |
+| tst.js:121:18:121:30 | Math.random() | tst.js:121:18:121:30 | Math.random() |
#select
| tst.js:2:20:2:32 | Math.random() | tst.js:2:20:2:32 | Math.random() | tst.js:2:20:2:32 | Math.random() | Cryptographically insecure $@ in a security context. | tst.js:2:20:2:32 | Math.random() | random value |
| tst.js:6:20:6:43 | "prefix ... andom() | tst.js:6:31:6:43 | Math.random() | tst.js:6:20:6:43 | "prefix ... andom() | Cryptographically insecure $@ in a security context. | tst.js:6:31:6:43 | Math.random() | random value |
@@ -131,3 +175,9 @@ edges
| tst.js:84:19:84:31 | Math.random() | tst.js:84:19:84:31 | Math.random() | tst.js:84:19:84:31 | Math.random() | Cryptographically insecure $@ in a security context. | tst.js:84:19:84:31 | Math.random() | random value |
| tst.js:90:32:90:44 | Math.random() | tst.js:90:32:90:44 | Math.random() | tst.js:90:32:90:44 | Math.random() | Cryptographically insecure $@ in a security context. | tst.js:90:32:90:44 | Math.random() | random value |
| tst.js:95:33:95:45 | Math.random() | tst.js:95:33:95:45 | Math.random() | tst.js:95:33:95:45 | Math.random() | Cryptographically insecure $@ in a security context. | tst.js:95:33:95:45 | Math.random() | random value |
+| tst.js:115:16:115:56 | Math.fl ... 00_000) | tst.js:115:27:115:39 | Math.random() | tst.js:115:16:115:56 | Math.fl ... 00_000) | Cryptographically insecure $@ in a security context. | tst.js:115:27:115:39 | Math.random() | random value |
+| tst.js:116:22:116:62 | Math.fl ... 00_000) | tst.js:116:33:116:45 | Math.random() | tst.js:116:22:116:62 | Math.fl ... 00_000) | Cryptographically insecure $@ in a security context. | tst.js:116:33:116:45 | Math.random() | random value |
+| tst.js:117:15:117:55 | Math.fl ... 00_000) | tst.js:117:26:117:38 | Math.random() | tst.js:117:15:117:55 | Math.fl ... 00_000) | Cryptographically insecure $@ in a security context. | tst.js:117:26:117:38 | Math.random() | random value |
+| tst.js:118:23:118:63 | Math.fl ... 00_000) | tst.js:118:34:118:46 | Math.random() | tst.js:118:23:118:63 | Math.fl ... 00_000) | Cryptographically insecure $@ in a security context. | tst.js:118:34:118:46 | Math.random() | random value |
+| tst.js:120:16:120:28 | Math.random() | tst.js:120:16:120:28 | Math.random() | tst.js:120:16:120:28 | Math.random() | Cryptographically insecure $@ in a security context. | tst.js:120:16:120:28 | Math.random() | random value |
+| tst.js:121:18:121:30 | Math.random() | tst.js:121:18:121:30 | Math.random() | tst.js:121:18:121:30 | Math.random() | Cryptographically insecure $@ in a security context. | tst.js:121:18:121:30 | Math.random() | random value |
diff --git a/javascript/ql/test/query-tests/Security/CWE-338/tst.js b/javascript/ql/test/query-tests/Security/CWE-338/tst.js
index 123799426b5..77393b8983c 100644
--- a/javascript/ql/test/query-tests/Security/CWE-338/tst.js
+++ b/javascript/ql/test/query-tests/Security/CWE-338/tst.js
@@ -109,4 +109,14 @@ function f18() {
}
};
var secret = genRandom(); // OK - Math.random() is only a fallback.
-})();
\ No newline at end of file
+})();
+
+function uid() {
+ var uuid = Math.floor(Math.random() * 4_000_000_000); // NOT OK
+ var sessionUid = Math.floor(Math.random() * 4_000_000_000); // NOT OK
+ var uid = Math.floor(Math.random() * 4_000_000_000); // NOT OK
+ var my_nice_uid = Math.floor(Math.random() * 4_000_000_000); // NOT OK
+ var liquid = Math.random(); // OK
+ var UUID = Math.random(); // NOT OK
+ var MY_UID = Math.random(); // NOK OK
+}
\ No newline at end of file
diff --git a/python/ql/src/Summary/LinesOfCode.ql b/python/ql/src/Summary/LinesOfCode.ql
index d9bfc4f872c..ad0b77730de 100644
--- a/python/ql/src/Summary/LinesOfCode.ql
+++ b/python/ql/src/Summary/LinesOfCode.ql
@@ -5,6 +5,7 @@
* database. This query counts the lines of code, excluding whitespace or comments.
* @kind metric
* @tags summary
+ * lines-of-code
* @id py/summary/lines-of-code
*/
diff --git a/python/ql/src/experimental/Security/CWE-730/RegexInjection.qhelp b/python/ql/src/experimental/Security/CWE-730/RegexInjection.qhelp
new file mode 100644
index 00000000000..f19f0744469
--- /dev/null
+++ b/python/ql/src/experimental/Security/CWE-730/RegexInjection.qhelp
@@ -0,0 +1,45 @@
+
+
+
+
+Constructing a regular expression with unsanitized user input is dangerous as a malicious user may
+be able to modify the meaning of the expression. In particular, such a user may be able to provide
+a regular expression fragment that takes exponential time in the worst case, and use that to
+perform a Denial of Service attack.
+
+
+
+
+
+Before embedding user input into a regular expression, use a sanitization function such as
+re.escape to escape meta-characters that have a special meaning regarding
+regular expressions' syntax.
+
+
+
+
+
+The following examples are based on a simple Flask web server environment.
+
+
+The following example shows a HTTP request parameter that is used to construct a regular expression
+without sanitizing it first:
+
+
+
+Instead, the request parameter should be sanitized first, for example using the function
+re.escape. This ensures that the user cannot insert characters which have a
+special meaning in regular expressions.
+
+
+
+
+
+OWASP: Regular expression Denial of Service - ReDoS.
+Wikipedia: ReDoS.
+Python docs: re.
+SonarSource: RSPEC-2631.
+
+
diff --git a/python/ql/src/experimental/Security/CWE-730/RegexInjection.ql b/python/ql/src/experimental/Security/CWE-730/RegexInjection.ql
new file mode 100644
index 00000000000..7725f636eb0
--- /dev/null
+++ b/python/ql/src/experimental/Security/CWE-730/RegexInjection.ql
@@ -0,0 +1,29 @@
+/**
+ * @name Regular expression injection
+ * @description User input should not be used in regular expressions without first being escaped,
+ * otherwise a malicious user may be able to inject an expression that could require
+ * exponential time on certain inputs.
+ * @kind path-problem
+ * @problem.severity error
+ * @id py/regex-injection
+ * @tags security
+ * external/cwe/cwe-730
+ * external/cwe/cwe-400
+ */
+
+// determine precision above
+import python
+import experimental.semmle.python.security.injection.RegexInjection
+import DataFlow::PathGraph
+
+from
+ RegexInjectionFlowConfig config, DataFlow::PathNode source, DataFlow::PathNode sink,
+ RegexInjectionSink regexInjectionSink, Attribute methodAttribute
+where
+ config.hasFlowPath(source, sink) and
+ regexInjectionSink = sink.getNode() and
+ methodAttribute = regexInjectionSink.getRegexMethod()
+select sink.getNode(), source, sink,
+ "$@ regular expression is constructed from a $@ and executed by $@.", sink.getNode(), "This",
+ source.getNode(), "user-provided value", methodAttribute,
+ regexInjectionSink.getRegexModule() + "." + methodAttribute.getName()
diff --git a/python/ql/src/experimental/Security/CWE-730/re_bad.py b/python/ql/src/experimental/Security/CWE-730/re_bad.py
new file mode 100644
index 00000000000..3befaba9a01
--- /dev/null
+++ b/python/ql/src/experimental/Security/CWE-730/re_bad.py
@@ -0,0 +1,15 @@
+from flask import request, Flask
+import re
+
+
+@app.route("/direct")
+def direct():
+ unsafe_pattern = request.args["pattern"]
+ re.search(unsafe_pattern, "")
+
+
+@app.route("/compile")
+def compile():
+ unsafe_pattern = request.args["pattern"]
+ compiled_pattern = re.compile(unsafe_pattern)
+ compiled_pattern.search("")
diff --git a/python/ql/src/experimental/Security/CWE-730/re_good.py b/python/ql/src/experimental/Security/CWE-730/re_good.py
new file mode 100644
index 00000000000..cdc9a7ac158
--- /dev/null
+++ b/python/ql/src/experimental/Security/CWE-730/re_good.py
@@ -0,0 +1,17 @@
+from flask import request, Flask
+import re
+
+
+@app.route("/direct")
+def direct():
+ unsafe_pattern = request.args['pattern']
+ safe_pattern = re.escape(unsafe_pattern)
+ re.search(safe_pattern, "")
+
+
+@app.route("/compile")
+def compile():
+ unsafe_pattern = request.args['pattern']
+ safe_pattern = re.escape(unsafe_pattern)
+ compiled_pattern = re.compile(safe_pattern)
+ compiled_pattern.search("")
diff --git a/python/ql/src/experimental/semmle/python/Concepts.qll b/python/ql/src/experimental/semmle/python/Concepts.qll
index 904b7967ee8..0661ebc5890 100644
--- a/python/ql/src/experimental/semmle/python/Concepts.qll
+++ b/python/ql/src/experimental/semmle/python/Concepts.qll
@@ -13,3 +13,70 @@ private import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.RemoteFlowSources
private import semmle.python.dataflow.new.TaintTracking
private import experimental.semmle.python.Frameworks
+
+/** Provides classes for modeling Regular Expression-related APIs. */
+module RegexExecution {
+ /**
+ * A data-flow node that executes a regular expression.
+ *
+ * Extend this class to model new APIs. If you want to refine existing API models,
+ * extend `RegexExecution` instead.
+ */
+ abstract class Range extends DataFlow::Node {
+ /**
+ * Gets the argument containing the executed expression.
+ */
+ abstract DataFlow::Node getRegexNode();
+
+ /**
+ * Gets the library used to execute the regular expression.
+ */
+ abstract string getRegexModule();
+ }
+}
+
+/**
+ * A data-flow node that executes a regular expression.
+ *
+ * Extend this class to refine existing API models. If you want to model new APIs,
+ * extend `RegexExecution::Range` instead.
+ */
+class RegexExecution extends DataFlow::Node {
+ RegexExecution::Range range;
+
+ RegexExecution() { this = range }
+
+ DataFlow::Node getRegexNode() { result = range.getRegexNode() }
+
+ string getRegexModule() { result = range.getRegexModule() }
+}
+
+/** Provides classes for modeling Regular Expression escape-related APIs. */
+module RegexEscape {
+ /**
+ * A data-flow node that escapes a regular expression.
+ *
+ * Extend this class to model new APIs. If you want to refine existing API models,
+ * extend `RegexEscape` instead.
+ */
+ abstract class Range extends DataFlow::Node {
+ /**
+ * Gets the argument containing the escaped expression.
+ */
+ abstract DataFlow::Node getRegexNode();
+ }
+}
+
+/**
+ * A data-flow node that escapes a regular expression.
+ *
+ * Extend this class to refine existing API models. If you want to model new APIs,
+ * extend `RegexEscape::Range` instead.
+ */
+class RegexEscape extends DataFlow::Node {
+ RegexEscape::Range range;
+
+ RegexEscape() { this = range }
+
+ DataFlow::Node getRegexNode() { result = range.getRegexNode() }
+}
diff --git a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
index 420caf0d73b..4f3457e0a99 100644
--- a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
+++ b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
@@ -9,3 +9,92 @@ private import semmle.python.dataflow.new.TaintTracking
private import semmle.python.dataflow.new.RemoteFlowSources
private import experimental.semmle.python.Concepts
private import semmle.python.ApiGraphs
+
+/**
+ * Provides models for Python's `re` library.
+ *
+ * See https://docs.python.org/3/library/re.html
+ */
+private module Re {
+ /**
+ * List of `re` methods immediately executing an expression.
+ *
+ * See https://docs.python.org/3/library/re.html#module-contents
+ */
+ private class RegexExecutionMethods extends string {
+ RegexExecutionMethods() {
+ this in ["match", "fullmatch", "search", "split", "findall", "finditer", "sub", "subn"]
+ }
+ }
+
+ /**
+ * A class to find `re` methods immediately executing an expression.
+ *
+ * See `RegexExecutionMethods`
+ */
+ private class DirectRegex extends DataFlow::CallCfgNode, RegexExecution::Range {
+ DataFlow::Node regexNode;
+
+ DirectRegex() {
+ this = API::moduleImport("re").getMember(any(RegexExecutionMethods m)).getACall() and
+ regexNode = this.getArg(0)
+ }
+
+ override DataFlow::Node getRegexNode() { result = regexNode }
+
+ override string getRegexModule() { result = "re" }
+ }
+
+ /**
+ * A class to find `re` methods immediately executing a compiled expression by `re.compile`.
+ *
+ * Given the following example:
+ *
+ * ```py
+ * pattern = re.compile(input)
+ * pattern.match(s)
+ * ```
+ *
+ * This class will identify that `re.compile` compiles `input` and afterwards
+ * executes `re`'s `match`. As a result, `this` will refer to `pattern.match(s)`
+ * and `this.getRegexNode()` will return the node for `input` (`re.compile`'s first argument)
+ *
+ *
+ * See `RegexExecutionMethods`
+ *
+ * See https://docs.python.org/3/library/re.html#regular-expression-objects
+ */
+ private class CompiledRegex extends DataFlow::CallCfgNode, RegexExecution::Range {
+ DataFlow::Node regexNode;
+
+ CompiledRegex() {
+ exists(DataFlow::CallCfgNode patternCall, DataFlow::AttrRead reMethod |
+ this.getFunction() = reMethod and
+ patternCall = API::moduleImport("re").getMember("compile").getACall() and
+ patternCall.flowsTo(reMethod.getObject()) and
+ reMethod.getAttributeName() instanceof RegexExecutionMethods and
+ regexNode = patternCall.getArg(0)
+ )
+ }
+
+ override DataFlow::Node getRegexNode() { result = regexNode }
+
+ override string getRegexModule() { result = "re" }
+ }
+
+ /**
+ * A class to find `re` methods escaping an expression.
+ *
+ * See https://docs.python.org/3/library/re.html#re.escape
+ */
+ class ReEscape extends DataFlow::CallCfgNode, RegexEscape::Range {
+ DataFlow::Node regexNode;
+
+ ReEscape() {
+ this = API::moduleImport("re").getMember("escape").getACall() and
+ regexNode = this.getArg(0)
+ }
+
+ override DataFlow::Node getRegexNode() { result = regexNode }
+ }
+}
diff --git a/python/ql/src/experimental/semmle/python/security/injection/RegexInjection.qll b/python/ql/src/experimental/semmle/python/security/injection/RegexInjection.qll
new file mode 100644
index 00000000000..7b7b08cacab
--- /dev/null
+++ b/python/ql/src/experimental/semmle/python/security/injection/RegexInjection.qll
@@ -0,0 +1,53 @@
+/**
+ * Provides a taint-tracking configuration for detecting regular expression injection
+ * vulnerabilities.
+ */
+
+import python
+import experimental.semmle.python.Concepts
+import semmle.python.dataflow.new.DataFlow
+import semmle.python.dataflow.new.TaintTracking
+import semmle.python.dataflow.new.RemoteFlowSources
+
+/**
+ * A class to find methods executing regular expressions.
+ *
+ * See `RegexExecution`
+ */
+class RegexInjectionSink extends DataFlow::Node {
+ string regexModule;
+ Attribute regexMethod;
+
+ RegexInjectionSink() {
+ exists(RegexExecution reExec |
+ this = reExec.getRegexNode() and
+ regexModule = reExec.getRegexModule() and
+ regexMethod = reExec.(DataFlow::CallCfgNode).getFunction().asExpr().(Attribute)
+ )
+ }
+
+ /**
+ * Gets the argument containing the executed expression.
+ */
+ string getRegexModule() { result = regexModule }
+
+ /**
+ * Gets the method used to execute the regular expression.
+ */
+ Attribute getRegexMethod() { result = regexMethod }
+}
+
+/**
+ * A taint-tracking configuration for detecting regular expression injections.
+ */
+class RegexInjectionFlowConfig extends TaintTracking::Configuration {
+ RegexInjectionFlowConfig() { this = "RegexInjectionFlowConfig" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof RegexInjectionSink }
+
+ override predicate isSanitizer(DataFlow::Node sanitizer) {
+ sanitizer = any(RegexEscape reEscape).getRegexNode()
+ }
+}
diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl.qll
index 9498e51e7e6..058d66b1496 100644
--- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl.qll
+++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl.qll
@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`.
*/
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
- (
- simpleLocalFlowStep(node1, node2) or
- reverseStepThroughInputOutputAlias(node1, node2)
- ) and
+ simpleLocalFlowStepExt(node1, node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
private predicate jumpStep(Node node1, Node node2, Configuration config) {
- jumpStep(node1, node2) and
+ jumpStepCached(node1, node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg)
)
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
- DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
+ DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) {
viableParamArg(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
- private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
- ) {
- exists(ParameterNode p |
+ private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
+ exists(ParamNode p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
- private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
+ private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
- DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
+ DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
+ DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
- DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/
private class FlowCheckNode extends Node {
FlowCheckNode() {
- this instanceof CastNode or
- clearsContent(this, _)
+ castNode(this) or
+ clearsContentCached(this, _)
}
}
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
- node instanceof ParameterNode or
+ node instanceof ParamNode or
node instanceof OutNodeExt or
store(_, _, node, _) or
read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
- not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
- t = getNodeType(node1)
+ t = getNodeDataFlowType(node1)
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
- t = getNodeType(node2)
+ t = getNodeDataFlowType(node2)
) and
node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and
- not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
- t = getNodeType(node2) and
+ t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
+ PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
}
bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap]
private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and
- if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
+ if node instanceof CastingNode
+ then compatibleTypes(getNodeDataFlowType(node), ap.getType())
+ else any()
}
bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
+ PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
}
bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
- DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx =
TSummaryCtxNone() or
- TSummaryCtxSome(ParameterNode p, AccessPath ap) {
+ TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
- private ParameterNode p;
+ private ParamNode p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
- ap = TAccessPathNil(getNodeType(node))
+ ap = TAccessPathNil(getNodeDataFlowType(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() }
private predicate isHidden() {
- nodeIsHidden(this.getNode()) and
+ hiddenNode(this.getNode()) and
not this.isSource() and
not this instanceof PathNodeSink
}
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
- ap = TAccessPathNil(getNodeType(node))
+ ap = TAccessPathNil(getNodeDataFlowType(node))
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
arg = mid.getNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
- PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
+ PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
- TSummaryCtx1Param(ParameterNode p)
+ TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
- not clearsContent(node, ap.getHead()) and
+ not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
)
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
- not clearsContent(node, ap.getHead().getContent()) and
+ not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode
- then compatibleTypes(getNodeType(node), ap.getType())
+ then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
)
}
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
(
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration()
)
or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and
- compatibleTypes(ap.getType(), getNodeType(node))
+ compatibleTypes(ap.getType(), getNodeDataFlowType(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
arg = mid.getNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
- PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
+ PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
- exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
+ exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
- exists(ParameterNode p |
+ exists(ParamNode p |
mid.getNode() = p and
viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
- exists(PartialPathNodeRev mid, ParameterNode p |
+ exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and
p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
- PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
+ PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl2.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl2.qll
index 9498e51e7e6..058d66b1496 100644
--- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl2.qll
+++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl2.qll
@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`.
*/
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
- (
- simpleLocalFlowStep(node1, node2) or
- reverseStepThroughInputOutputAlias(node1, node2)
- ) and
+ simpleLocalFlowStepExt(node1, node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
private predicate jumpStep(Node node1, Node node2, Configuration config) {
- jumpStep(node1, node2) and
+ jumpStepCached(node1, node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg)
)
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
- DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
+ DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) {
viableParamArg(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
- private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
- ) {
- exists(ParameterNode p |
+ private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
+ exists(ParamNode p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
- private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
+ private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
- DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
+ DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
+ DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
- DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/
private class FlowCheckNode extends Node {
FlowCheckNode() {
- this instanceof CastNode or
- clearsContent(this, _)
+ castNode(this) or
+ clearsContentCached(this, _)
}
}
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
- node instanceof ParameterNode or
+ node instanceof ParamNode or
node instanceof OutNodeExt or
store(_, _, node, _) or
read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
- not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
- t = getNodeType(node1)
+ t = getNodeDataFlowType(node1)
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
- t = getNodeType(node2)
+ t = getNodeDataFlowType(node2)
) and
node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and
- not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
- t = getNodeType(node2) and
+ t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
+ PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
}
bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap]
private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and
- if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
+ if node instanceof CastingNode
+ then compatibleTypes(getNodeDataFlowType(node), ap.getType())
+ else any()
}
bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
+ PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
}
bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
- DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx =
TSummaryCtxNone() or
- TSummaryCtxSome(ParameterNode p, AccessPath ap) {
+ TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
- private ParameterNode p;
+ private ParamNode p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
- ap = TAccessPathNil(getNodeType(node))
+ ap = TAccessPathNil(getNodeDataFlowType(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() }
private predicate isHidden() {
- nodeIsHidden(this.getNode()) and
+ hiddenNode(this.getNode()) and
not this.isSource() and
not this instanceof PathNodeSink
}
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
- ap = TAccessPathNil(getNodeType(node))
+ ap = TAccessPathNil(getNodeDataFlowType(node))
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
arg = mid.getNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
- PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
+ PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
- TSummaryCtx1Param(ParameterNode p)
+ TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
- not clearsContent(node, ap.getHead()) and
+ not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
)
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
- not clearsContent(node, ap.getHead().getContent()) and
+ not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode
- then compatibleTypes(getNodeType(node), ap.getType())
+ then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
)
}
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
(
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration()
)
or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and
- compatibleTypes(ap.getType(), getNodeType(node))
+ compatibleTypes(ap.getType(), getNodeDataFlowType(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
arg = mid.getNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
- PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
+ PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
- exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
+ exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
- exists(ParameterNode p |
+ exists(ParamNode p |
mid.getNode() = p and
viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
- exists(PartialPathNodeRev mid, ParameterNode p |
+ exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and
p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
- PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
+ PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl3.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl3.qll
index 9498e51e7e6..058d66b1496 100644
--- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl3.qll
+++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl3.qll
@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`.
*/
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
- (
- simpleLocalFlowStep(node1, node2) or
- reverseStepThroughInputOutputAlias(node1, node2)
- ) and
+ simpleLocalFlowStepExt(node1, node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
private predicate jumpStep(Node node1, Node node2, Configuration config) {
- jumpStep(node1, node2) and
+ jumpStepCached(node1, node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg)
)
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
- DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
+ DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) {
viableParamArg(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
- private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
- ) {
- exists(ParameterNode p |
+ private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
+ exists(ParamNode p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
- private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
+ private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
- DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
+ DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
+ DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
- DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/
private class FlowCheckNode extends Node {
FlowCheckNode() {
- this instanceof CastNode or
- clearsContent(this, _)
+ castNode(this) or
+ clearsContentCached(this, _)
}
}
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
- node instanceof ParameterNode or
+ node instanceof ParamNode or
node instanceof OutNodeExt or
store(_, _, node, _) or
read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
- not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
- t = getNodeType(node1)
+ t = getNodeDataFlowType(node1)
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
- t = getNodeType(node2)
+ t = getNodeDataFlowType(node2)
) and
node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and
- not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
- t = getNodeType(node2) and
+ t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
+ PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
}
bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap]
private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and
- if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
+ if node instanceof CastingNode
+ then compatibleTypes(getNodeDataFlowType(node), ap.getType())
+ else any()
}
bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
+ PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
}
bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
- DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx =
TSummaryCtxNone() or
- TSummaryCtxSome(ParameterNode p, AccessPath ap) {
+ TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
- private ParameterNode p;
+ private ParamNode p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
- ap = TAccessPathNil(getNodeType(node))
+ ap = TAccessPathNil(getNodeDataFlowType(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() }
private predicate isHidden() {
- nodeIsHidden(this.getNode()) and
+ hiddenNode(this.getNode()) and
not this.isSource() and
not this instanceof PathNodeSink
}
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
- ap = TAccessPathNil(getNodeType(node))
+ ap = TAccessPathNil(getNodeDataFlowType(node))
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
arg = mid.getNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
- PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
+ PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
- TSummaryCtx1Param(ParameterNode p)
+ TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
- not clearsContent(node, ap.getHead()) and
+ not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
)
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
- not clearsContent(node, ap.getHead().getContent()) and
+ not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode
- then compatibleTypes(getNodeType(node), ap.getType())
+ then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
)
}
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
(
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration()
)
or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and
- compatibleTypes(ap.getType(), getNodeType(node))
+ compatibleTypes(ap.getType(), getNodeDataFlowType(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
arg = mid.getNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
- PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
+ PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
- exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
+ exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
- exists(ParameterNode p |
+ exists(ParamNode p |
mid.getNode() = p and
viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
- exists(PartialPathNodeRev mid, ParameterNode p |
+ exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and
p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
- PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
+ PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl4.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl4.qll
index 9498e51e7e6..058d66b1496 100644
--- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl4.qll
+++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl4.qll
@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`.
*/
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
- (
- simpleLocalFlowStep(node1, node2) or
- reverseStepThroughInputOutputAlias(node1, node2)
- ) and
+ simpleLocalFlowStepExt(node1, node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
private predicate jumpStep(Node node1, Node node2, Configuration config) {
- jumpStep(node1, node2) and
+ jumpStepCached(node1, node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg)
)
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
- DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
+ DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) {
viableParamArg(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
- private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
- ) {
- exists(ParameterNode p |
+ private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
+ exists(ParamNode p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
- private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
+ private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
- DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
+ DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
+ DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
- DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
- DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/
private class FlowCheckNode extends Node {
FlowCheckNode() {
- this instanceof CastNode or
- clearsContent(this, _)
+ castNode(this) or
+ clearsContentCached(this, _)
}
}
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
- node instanceof ParameterNode or
+ node instanceof ParamNode or
node instanceof OutNodeExt or
store(_, _, node, _) or
read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
- not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
- t = getNodeType(node1)
+ t = getNodeDataFlowType(node1)
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
- t = getNodeType(node2)
+ t = getNodeDataFlowType(node2)
) and
node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and
- not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
- t = getNodeType(node2) and
+ t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
+ PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
}
bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap]
private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and
- if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
+ if node instanceof CastingNode
+ then compatibleTypes(getNodeDataFlowType(node), ap.getType())
+ else any()
}
bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) {
- PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
+ PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
}
bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
- DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
- Configuration config
+ DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
- DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
+ DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
- exists(ArgumentNode arg, boolean allowsFieldFlow |
+ exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowIn(
- DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
- Configuration config
+ DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
- exists(ParameterNode p, boolean allowsFieldFlow |
+ exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
- DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
+ DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
- ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
+ ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
- predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
+ predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx =
TSummaryCtxNone() or
- TSummaryCtxSome(ParameterNode p, AccessPath ap) {
+ TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
- private ParameterNode p;
+ private ParamNode p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
- ap = TAccessPathNil(getNodeType(node))
+ ap = TAccessPathNil(getNodeDataFlowType(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() }
private predicate isHidden() {
- nodeIsHidden(this.getNode()) and
+ hiddenNode(this.getNode()) and
not this.isSource() and
not this instanceof PathNodeSink
}
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
- ap = TAccessPathNil(getNodeType(node))
+ ap = TAccessPathNil(getNodeDataFlowType(node))
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
arg = mid.getNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
- exists(ParameterNode p |
+ exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
- PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
+ PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
- TSummaryCtx1Param(ParameterNode p)
+ TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
- not clearsContent(node, ap.getHead()) and
+ not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
)
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
- not clearsContent(node, ap.getHead().getContent()) and
+ not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode
- then compatibleTypes(getNodeType(node), ap.getType())
+ then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
)
}
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
- not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
+ not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
(
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration()
)
or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
- ap = TPartialNil(getNodeType(node)) and
+ ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and
- compatibleTypes(ap.getType(), getNodeType(node))
+ compatibleTypes(ap.getType(), getNodeDataFlowType(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
arg = mid.getNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
- PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
+ PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
- exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
+ exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
- exists(ParameterNode p |
+ exists(ParamNode p |
mid.getNode() = p and
viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
- exists(PartialPathNodeRev mid, ParameterNode p |
+ exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and
p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
- PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
+ PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll
index 966c30038cc..462e89ac9ed 100644
--- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll
+++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll
@@ -35,22 +35,22 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
*/
private module LambdaFlow {
- private predicate viableParamNonLambda(DataFlowCall call, int i, ParameterNode p) {
+ private predicate viableParamNonLambda(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallable(call), i)
}
- private predicate viableParamLambda(DataFlowCall call, int i, ParameterNode p) {
+ private predicate viableParamLambda(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallableLambda(call, _), i)
}
- private predicate viableParamArgNonLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
+ private predicate viableParamArgNonLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i |
viableParamNonLambda(call, i, p) and
arg.argumentOf(call, i)
)
}
- private predicate viableParamArgLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
+ private predicate viableParamArgLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i |
viableParamLambda(call, i, p) and
arg.argumentOf(call, i)
@@ -118,8 +118,8 @@ private module LambdaFlow {
boolean toJump, DataFlowCallOption lastCall
) {
revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and
- if node instanceof CastNode or node instanceof ArgumentNode or node instanceof ReturnNode
- then compatibleTypes(t, getNodeType(node))
+ if castNode(node) or node instanceof ArgNode or node instanceof ReturnNode
+ then compatibleTypes(t, getNodeDataFlowType(node))
else any()
}
@@ -129,7 +129,7 @@ private module LambdaFlow {
boolean toJump, DataFlowCallOption lastCall
) {
lambdaCall(lambdaCall, kind, node) and
- t = getNodeType(node) and
+ t = getNodeDataFlowType(node) and
toReturn = false and
toJump = false and
lastCall = TDataFlowCallNone()
@@ -146,7 +146,7 @@ private module LambdaFlow {
getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid)
|
preservesValue = false and
- t = getNodeType(node)
+ t = getNodeDataFlowType(node)
or
preservesValue = true and
t = t0
@@ -160,7 +160,7 @@ private module LambdaFlow {
toJump = true and
lastCall = TDataFlowCallNone()
|
- jumpStep(node, mid) and
+ jumpStepCached(node, mid) and
t = t0
or
exists(boolean preservesValue |
@@ -168,7 +168,7 @@ private module LambdaFlow {
getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid)
|
preservesValue = false and
- t = getNodeType(node)
+ t = getNodeDataFlowType(node)
or
preservesValue = true and
t = t0
@@ -176,7 +176,7 @@ private module LambdaFlow {
)
or
// flow into a callable
- exists(ParameterNode p, DataFlowCallOption lastCall0, DataFlowCall call |
+ exists(ParamNode p, DataFlowCallOption lastCall0, DataFlowCall call |
revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and
(
if lastCall0 = TDataFlowCallNone() and toJump = false
@@ -227,7 +227,7 @@ private module LambdaFlow {
pragma[nomagic]
predicate revLambdaFlowIn(
- DataFlowCall lambdaCall, LambdaCallKind kind, ParameterNode p, DataFlowType t, boolean toJump,
+ DataFlowCall lambdaCall, LambdaCallKind kind, ParamNode p, DataFlowType t, boolean toJump,
DataFlowCallOption lastCall
) {
revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall)
@@ -242,6 +242,89 @@ private DataFlowCallable viableCallableExt(DataFlowCall call) {
cached
private module Cached {
+ /**
+ * If needed, call this predicate from `DataFlowImplSpecific.qll` in order to
+ * force a stage-dependency on the `DataFlowImplCommon.qll` stage and therby
+ * collapsing the two stages.
+ */
+ cached
+ predicate forceCachingInSameStage() { any() }
+
+ cached
+ predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = n.getEnclosingCallable() }
+
+ cached
+ predicate callEnclosingCallable(DataFlowCall call, DataFlowCallable c) {
+ c = call.getEnclosingCallable()
+ }
+
+ cached
+ predicate nodeDataFlowType(Node n, DataFlowType t) { t = getNodeType(n) }
+
+ cached
+ predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
+
+ cached
+ predicate clearsContentCached(Node n, Content c) { clearsContent(n, c) }
+
+ cached
+ predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
+
+ cached
+ predicate outNodeExt(Node n) {
+ n instanceof OutNode
+ or
+ n.(PostUpdateNode).getPreUpdateNode() instanceof ArgNode
+ }
+
+ cached
+ predicate hiddenNode(Node n) { nodeIsHidden(n) }
+
+ cached
+ OutNodeExt getAnOutNodeExt(DataFlowCall call, ReturnKindExt k) {
+ result = getAnOutNode(call, k.(ValueReturnKind).getKind())
+ or
+ exists(ArgNode arg |
+ result.(PostUpdateNode).getPreUpdateNode() = arg and
+ arg.argumentOf(call, k.(ParamUpdateReturnKind).getPosition())
+ )
+ }
+
+ cached
+ predicate returnNodeExt(Node n, ReturnKindExt k) {
+ k = TValueReturn(n.(ReturnNode).getKind())
+ or
+ exists(ParamNode p, int pos |
+ parameterValueFlowsToPreUpdate(p, n) and
+ p.isParameterOf(_, pos) and
+ k = TParamUpdate(pos)
+ )
+ }
+
+ cached
+ predicate castNode(Node n) { n instanceof CastNode }
+
+ cached
+ predicate castingNode(Node n) {
+ castNode(n) or
+ n instanceof ParamNode or
+ n instanceof OutNodeExt or
+ // For reads, `x.f`, we want to check that the tracked type after the read (which
+ // is obtained by popping the head of the access path stack) is compatible with
+ // the type of `x.f`.
+ read(_, _, n)
+ }
+
+ cached
+ predicate parameterNode(Node n, DataFlowCallable c, int i) {
+ n.(ParameterNode).isParameterOf(c, i)
+ }
+
+ cached
+ predicate argumentNode(Node n, DataFlowCall call, int pos) {
+ n.(ArgumentNode).argumentOf(call, pos)
+ }
+
/**
* Gets a viable target for the lambda call `call`.
*
@@ -261,7 +344,7 @@ private module Cached {
* The instance parameter is considered to have index `-1`.
*/
pragma[nomagic]
- private predicate viableParam(DataFlowCall call, int i, ParameterNode p) {
+ private predicate viableParam(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallableExt(call), i)
}
@@ -270,11 +353,11 @@ private module Cached {
* dispatch into account.
*/
cached
- predicate viableParamArg(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
+ predicate viableParamArg(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i |
viableParam(call, i, p) and
arg.argumentOf(call, i) and
- compatibleTypes(getNodeType(arg), getNodeType(p))
+ compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
)
}
@@ -312,7 +395,7 @@ private module Cached {
* `read` indicates whether it is contents of `p` that can flow to `node`.
*/
pragma[nomagic]
- private predicate parameterValueFlowCand(ParameterNode p, Node node, boolean read) {
+ private predicate parameterValueFlowCand(ParamNode p, Node node, boolean read) {
p = node and
read = false
or
@@ -325,30 +408,30 @@ private module Cached {
// read
exists(Node mid |
parameterValueFlowCand(p, mid, false) and
- readStep(mid, _, node) and
+ read(mid, _, node) and
read = true
)
or
// flow through: no prior read
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
parameterValueFlowArgCand(p, arg, false) and
argumentValueFlowsThroughCand(arg, node, read)
)
or
// flow through: no read inside method
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
parameterValueFlowArgCand(p, arg, read) and
argumentValueFlowsThroughCand(arg, node, false)
)
}
pragma[nomagic]
- private predicate parameterValueFlowArgCand(ParameterNode p, ArgumentNode arg, boolean read) {
+ private predicate parameterValueFlowArgCand(ParamNode p, ArgNode arg, boolean read) {
parameterValueFlowCand(p, arg, read)
}
pragma[nomagic]
- predicate parameterValueFlowsToPreUpdateCand(ParameterNode p, PostUpdateNode n) {
+ predicate parameterValueFlowsToPreUpdateCand(ParamNode p, PostUpdateNode n) {
parameterValueFlowCand(p, n.getPreUpdateNode(), false)
}
@@ -360,7 +443,7 @@ private module Cached {
* `read` indicates whether it is contents of `p` that can flow to the return
* node.
*/
- predicate parameterValueFlowReturnCand(ParameterNode p, ReturnKind kind, boolean read) {
+ predicate parameterValueFlowReturnCand(ParamNode p, ReturnKind kind, boolean read) {
exists(ReturnNode ret |
parameterValueFlowCand(p, ret, read) and
kind = ret.getKind()
@@ -369,9 +452,9 @@ private module Cached {
pragma[nomagic]
private predicate argumentValueFlowsThroughCand0(
- DataFlowCall call, ArgumentNode arg, ReturnKind kind, boolean read
+ DataFlowCall call, ArgNode arg, ReturnKind kind, boolean read
) {
- exists(ParameterNode param | viableParamArg(call, param, arg) |
+ exists(ParamNode param | viableParamArg(call, param, arg) |
parameterValueFlowReturnCand(param, kind, read)
)
}
@@ -382,14 +465,14 @@ private module Cached {
*
* `read` indicates whether it is contents of `arg` that can flow to `out`.
*/
- predicate argumentValueFlowsThroughCand(ArgumentNode arg, Node out, boolean read) {
+ predicate argumentValueFlowsThroughCand(ArgNode arg, Node out, boolean read) {
exists(DataFlowCall call, ReturnKind kind |
argumentValueFlowsThroughCand0(call, arg, kind, read) and
out = getAnOutNode(call, kind)
)
}
- predicate cand(ParameterNode p, Node n) {
+ predicate cand(ParamNode p, Node n) {
parameterValueFlowCand(p, n, _) and
(
parameterValueFlowReturnCand(p, _, _)
@@ -416,21 +499,21 @@ private module Cached {
* If a read step was taken, then `read` captures the `Content`, the
* container type, and the content type.
*/
- predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) {
+ predicate parameterValueFlow(ParamNode p, Node node, ReadStepTypesOption read) {
parameterValueFlow0(p, node, read) and
if node instanceof CastingNode
then
// normal flow through
read = TReadStepTypesNone() and
- compatibleTypes(getNodeType(p), getNodeType(node))
+ compatibleTypes(getNodeDataFlowType(p), getNodeDataFlowType(node))
or
// getter
- compatibleTypes(read.getContentType(), getNodeType(node))
+ compatibleTypes(read.getContentType(), getNodeDataFlowType(node))
else any()
}
pragma[nomagic]
- private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) {
+ private predicate parameterValueFlow0(ParamNode p, Node node, ReadStepTypesOption read) {
p = node and
Cand::cand(p, _) and
read = TReadStepTypesNone()
@@ -447,7 +530,7 @@ private module Cached {
readStepWithTypes(mid, read.getContainerType(), read.getContent(), node,
read.getContentType()) and
Cand::parameterValueFlowReturnCand(p, _, true) and
- compatibleTypes(getNodeType(p), read.getContainerType())
+ compatibleTypes(getNodeDataFlowType(p), read.getContainerType())
)
or
parameterValueFlow0_0(TReadStepTypesNone(), p, node, read)
@@ -455,34 +538,32 @@ private module Cached {
pragma[nomagic]
private predicate parameterValueFlow0_0(
- ReadStepTypesOption mustBeNone, ParameterNode p, Node node, ReadStepTypesOption read
+ ReadStepTypesOption mustBeNone, ParamNode p, Node node, ReadStepTypesOption read
) {
// flow through: no prior read
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
parameterValueFlowArg(p, arg, mustBeNone) and
argumentValueFlowsThrough(arg, read, node)
)
or
// flow through: no read inside method
- exists(ArgumentNode arg |
+ exists(ArgNode arg |
parameterValueFlowArg(p, arg, read) and
argumentValueFlowsThrough(arg, mustBeNone, node)
)
}
pragma[nomagic]
- private predicate parameterValueFlowArg(
- ParameterNode p, ArgumentNode arg, ReadStepTypesOption read
- ) {
+ private predicate parameterValueFlowArg(ParamNode p, ArgNode arg, ReadStepTypesOption read) {
parameterValueFlow(p, arg, read) and
Cand::argumentValueFlowsThroughCand(arg, _, _)
}
pragma[nomagic]
private predicate argumentValueFlowsThrough0(
- DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read
+ DataFlowCall call, ArgNode arg, ReturnKind kind, ReadStepTypesOption read
) {
- exists(ParameterNode param | viableParamArg(call, param, arg) |
+ exists(ParamNode param | viableParamArg(call, param, arg) |
parameterValueFlowReturn(param, kind, read)
)
}
@@ -496,18 +577,18 @@ private module Cached {
* container type, and the content type.
*/
pragma[nomagic]
- predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) {
+ predicate argumentValueFlowsThrough(ArgNode arg, ReadStepTypesOption read, Node out) {
exists(DataFlowCall call, ReturnKind kind |
argumentValueFlowsThrough0(call, arg, kind, read) and
out = getAnOutNode(call, kind)
|
// normal flow through
read = TReadStepTypesNone() and
- compatibleTypes(getNodeType(arg), getNodeType(out))
+ compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(out))
or
// getter
- compatibleTypes(getNodeType(arg), read.getContainerType()) and
- compatibleTypes(read.getContentType(), getNodeType(out))
+ compatibleTypes(getNodeDataFlowType(arg), read.getContainerType()) and
+ compatibleTypes(read.getContentType(), getNodeDataFlowType(out))
)
}
@@ -516,7 +597,7 @@ private module Cached {
* value-preserving steps and a single read step, not taking call
* contexts into account, thus representing a getter-step.
*/
- predicate getterStep(ArgumentNode arg, Content c, Node out) {
+ predicate getterStep(ArgNode arg, Content c, Node out) {
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
}
@@ -529,7 +610,7 @@ private module Cached {
* container type, and the content type.
*/
private predicate parameterValueFlowReturn(
- ParameterNode p, ReturnKind kind, ReadStepTypesOption read
+ ParamNode p, ReturnKind kind, ReadStepTypesOption read
) {
exists(ReturnNode ret |
parameterValueFlow(p, ret, read) and
@@ -553,7 +634,7 @@ private module Cached {
private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) {
mayBenefitFromCallContext(call, callable)
or
- callable = call.getEnclosingCallable() and
+ callEnclosingCallable(call, callable) and
exists(viableCallableLambda(call, TDataFlowCallSome(_)))
}
@@ -611,7 +692,7 @@ private module Cached {
mayBenefitFromCallContextExt(call, _) and
c = viableCallableExt(call) and
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and
- tgts = strictcount(DataFlowCall ctx | viableCallableExt(ctx) = call.getEnclosingCallable()) and
+ tgts = strictcount(DataFlowCall ctx | callEnclosingCallable(call, viableCallableExt(ctx))) and
ctxtgts < tgts
)
}
@@ -635,8 +716,7 @@ private module Cached {
* Holds if `p` can flow to the pre-update node associated with post-update
* node `n`, in the same callable, using only value-preserving steps.
*/
- cached
- predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) {
+ private predicate parameterValueFlowsToPreUpdate(ParamNode p, PostUpdateNode n) {
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
}
@@ -644,9 +724,9 @@ private module Cached {
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
) {
storeStep(node1, c, node2) and
- readStep(_, c, _) and
- contentType = getNodeType(node1) and
- containerType = getNodeType(node2)
+ read(_, c, _) and
+ contentType = getNodeDataFlowType(node1) and
+ containerType = getNodeDataFlowType(node2)
or
exists(Node n1, Node n2 |
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
@@ -654,12 +734,15 @@ private module Cached {
|
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
or
- readStep(n2, c, n1) and
- contentType = getNodeType(n1) and
- containerType = getNodeType(n2)
+ read(n2, c, n1) and
+ contentType = getNodeDataFlowType(n1) and
+ containerType = getNodeDataFlowType(n2)
)
}
+ cached
+ predicate read(Node node1, Content c, Node node2) { readStep(node1, c, node2) }
+
/**
* Holds if data can flow from `node1` to `node2` via a direct assignment to
* `f`.
@@ -678,8 +761,9 @@ private module Cached {
* are aliases. A typical example is a function returning `this`, implementing a fluent
* interface.
*/
- cached
- predicate reverseStepThroughInputOutputAlias(PostUpdateNode fromNode, PostUpdateNode toNode) {
+ private predicate reverseStepThroughInputOutputAlias(
+ PostUpdateNode fromNode, PostUpdateNode toNode
+ ) {
exists(Node fromPre, Node toPre |
fromPre = fromNode.getPreUpdateNode() and
toPre = toNode.getPreUpdateNode()
@@ -688,14 +772,20 @@ private module Cached {
// Does the language-specific simpleLocalFlowStep already model flow
// from function input to output?
fromPre = getAnOutNode(c, _) and
- toPre.(ArgumentNode).argumentOf(c, _) and
- simpleLocalFlowStep(toPre.(ArgumentNode), fromPre)
+ toPre.(ArgNode).argumentOf(c, _) and
+ simpleLocalFlowStep(toPre.(ArgNode), fromPre)
)
or
argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre)
)
}
+ cached
+ predicate simpleLocalFlowStepExt(Node node1, Node node2) {
+ simpleLocalFlowStep(node1, node2) or
+ reverseStepThroughInputOutputAlias(node1, node2)
+ }
+
/**
* Holds if the call context `call` either improves virtual dispatch in
* `callable` or if it allows us to prune unreachable nodes in `callable`.
@@ -704,7 +794,7 @@ private module Cached {
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
reducedViableImplInCallContext(_, callable, call)
or
- exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCall(n, call))
+ exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call))
}
cached
@@ -726,12 +816,12 @@ private module Cached {
cached
newtype TLocalFlowCallContext =
TAnyLocalCall() or
- TSpecificLocalCall(DataFlowCall call) { isUnreachableInCall(_, call) }
+ TSpecificLocalCall(DataFlowCall call) { isUnreachableInCallCached(_, call) }
cached
newtype TReturnKindExt =
TValueReturn(ReturnKind kind) or
- TParamUpdate(int pos) { exists(ParameterNode p | p.isParameterOf(_, pos)) }
+ TParamUpdate(int pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
cached
newtype TBooleanOption =
@@ -761,23 +851,15 @@ private module Cached {
* A `Node` at which a cast can occur such that the type should be checked.
*/
class CastingNode extends Node {
- CastingNode() {
- this instanceof ParameterNode or
- this instanceof CastNode or
- this instanceof OutNodeExt or
- // For reads, `x.f`, we want to check that the tracked type after the read (which
- // is obtained by popping the head of the access path stack) is compatible with
- // the type of `x.f`.
- readStep(_, _, this)
- }
+ CastingNode() { castingNode(this) }
}
private predicate readStepWithTypes(
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
) {
- readStep(n1, c, n2) and
- container = getNodeType(n1) and
- content = getNodeType(n2)
+ read(n1, c, n2) and
+ container = getNodeDataFlowType(n1) and
+ content = getNodeDataFlowType(n2)
}
private newtype TReadStepTypesOption =
@@ -854,7 +936,7 @@ class CallContextSomeCall extends CallContextCall, TSomeCall {
override string toString() { result = "CcSomeCall" }
override predicate relevantFor(DataFlowCallable callable) {
- exists(ParameterNode p | getNodeEnclosingCallable(p) = callable)
+ exists(ParamNode p | getNodeEnclosingCallable(p) = callable)
}
override predicate matchesCall(DataFlowCall call) { any() }
@@ -866,7 +948,7 @@ class CallContextReturn extends CallContextNoCall, TReturn {
}
override predicate relevantFor(DataFlowCallable callable) {
- exists(DataFlowCall call | this = TReturn(_, call) and call.getEnclosingCallable() = callable)
+ exists(DataFlowCall call | this = TReturn(_, call) and callEnclosingCallable(call, callable))
}
}
@@ -899,7 +981,7 @@ class LocalCallContextSpecificCall extends LocalCallContext, TSpecificLocalCall
}
private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) {
- exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCall(n, call))
+ exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCallCached(n, call))
}
/**
@@ -913,26 +995,37 @@ LocalCallContext getLocalCallContext(CallContext ctx, DataFlowCallable callable)
else result instanceof LocalCallContextAny
}
+/**
+ * The value of a parameter at function entry, viewed as a node in a data
+ * flow graph.
+ */
+class ParamNode extends Node {
+ ParamNode() { parameterNode(this, _, _) }
+
+ /**
+ * Holds if this node is the parameter of callable `c` at the specified
+ * (zero-based) position.
+ */
+ predicate isParameterOf(DataFlowCallable c, int i) { parameterNode(this, c, i) }
+}
+
+/** A data-flow node that represents a call argument. */
+class ArgNode extends Node {
+ ArgNode() { argumentNode(this, _, _) }
+
+ /** Holds if this argument occurs at the given position in the given call. */
+ final predicate argumentOf(DataFlowCall call, int pos) { argumentNode(this, call, pos) }
+}
+
/**
* A node from which flow can return to the caller. This is either a regular
* `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter.
*/
class ReturnNodeExt extends Node {
- ReturnNodeExt() {
- this instanceof ReturnNode or
- parameterValueFlowsToPreUpdate(_, this)
- }
+ ReturnNodeExt() { returnNodeExt(this, _) }
/** Gets the kind of this returned value. */
- ReturnKindExt getKind() {
- result = TValueReturn(this.(ReturnNode).getKind())
- or
- exists(ParameterNode p, int pos |
- parameterValueFlowsToPreUpdate(p, this) and
- p.isParameterOf(_, pos) and
- result = TParamUpdate(pos)
- )
- }
+ ReturnKindExt getKind() { returnNodeExt(this, result) }
}
/**
@@ -940,11 +1033,7 @@ class ReturnNodeExt extends Node {
* or a post-update node associated with a call argument.
*/
class OutNodeExt extends Node {
- OutNodeExt() {
- this instanceof OutNode
- or
- this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode
- }
+ OutNodeExt() { outNodeExt(this) }
}
/**
@@ -957,7 +1046,7 @@ abstract class ReturnKindExt extends TReturnKindExt {
abstract string toString();
/** Gets a node corresponding to data flow out of `call`. */
- abstract OutNodeExt getAnOutNode(DataFlowCall call);
+ final OutNodeExt getAnOutNode(DataFlowCall call) { result = getAnOutNodeExt(call, this) }
}
class ValueReturnKind extends ReturnKindExt, TValueReturn {
@@ -968,10 +1057,6 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn {
ReturnKind getKind() { result = kind }
override string toString() { result = kind.toString() }
-
- override OutNodeExt getAnOutNode(DataFlowCall call) {
- result = getAnOutNode(call, this.getKind())
- }
}
class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
@@ -982,13 +1067,6 @@ class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
int getPosition() { result = pos }
override string toString() { result = "param update " + pos }
-
- override OutNodeExt getAnOutNode(DataFlowCall call) {
- exists(ArgumentNode arg |
- result.(PostUpdateNode).getPreUpdateNode() = arg and
- arg.argumentOf(call, this.getPosition())
- )
- }
}
/** A callable tagged with a relevant return kind. */
@@ -1015,10 +1093,13 @@ class ReturnPosition extends TReturnPosition0 {
*/
pragma[inline]
DataFlowCallable getNodeEnclosingCallable(Node n) {
- exists(Node n0 |
- pragma[only_bind_into](n0) = n and
- pragma[only_bind_into](result) = n0.getEnclosingCallable()
- )
+ nodeEnclosingCallable(pragma[only_bind_out](n), pragma[only_bind_into](result))
+}
+
+/** Gets the type of `n` used for type pruning. */
+pragma[inline]
+DataFlowType getNodeDataFlowType(Node n) {
+ nodeDataFlowType(pragma[only_bind_out](n), pragma[only_bind_into](result))
}
pragma[noinline]
@@ -1042,7 +1123,7 @@ predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall
cc instanceof CallContextAny and callable = viableCallableExt(call)
or
exists(DataFlowCallable c0, DataFlowCall call0 |
- call0.getEnclosingCallable() = callable and
+ callEnclosingCallable(call0, callable) and
cc = TReturn(c0, call0) and
c0 = prunedViableImplInCallContextReverse(call0, call)
)
@@ -1063,8 +1144,6 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
result = viableCallableExt(call) and cc instanceof CallContextReturn
}
-predicate read = readStep/3;
-
/** An optional Boolean value. */
class BooleanOption extends TBooleanOption {
string toString() {
@@ -1116,7 +1195,7 @@ abstract class AccessPathFront extends TAccessPathFront {
TypedContent getHead() { this = TFrontHead(result) }
- predicate isClearedAt(Node n) { clearsContent(n, getHead().getContent()) }
+ predicate isClearedAt(Node n) { clearsContentCached(n, getHead().getContent()) }
}
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll
index 82c1751bb07..074289b00fd 100644
--- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll
+++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll
@@ -228,7 +228,6 @@ module EssaFlow {
* data flow. It is a strict subset of the `localFlowStep` predicate, as it
* excludes SSA flow through instance fields.
*/
-cached
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
// If there is ESSA-flow out of a node `node`, we want flow
// both out of `node` and any post-update node of `node`.
@@ -1559,7 +1558,6 @@ predicate kwUnpackReadStep(CfgNode nodeFrom, DictionaryElementContent c, Node no
* any value stored inside `f` is cleared at the pre-update node associated with `x`
* in `x.f = newValue`.
*/
-cached
predicate clearsContent(Node n, Content c) {
exists(CallNode call, CallableValue callable, string name |
call_unpacks(call, _, callable, name, _) and
diff --git a/python/ql/src/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll b/python/ql/src/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll
index f12d97d2fa5..a6e169243db 100644
--- a/python/ql/src/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll
+++ b/python/ql/src/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll
@@ -9,36 +9,42 @@ private import semmle.python.dataflow.new.internal.TaintTrackingPublic
*/
predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
-/**
- * Holds if the additional step from `nodeFrom` to `nodeTo` should be included in all
- * global taint flow configurations.
- */
-predicate defaultAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
- localAdditionalTaintStep(nodeFrom, nodeTo)
- or
- any(AdditionalTaintStep a).step(nodeFrom, nodeTo)
+private module Cached {
+ /**
+ * Holds if the additional step from `nodeFrom` to `nodeTo` should be included in all
+ * global taint flow configurations.
+ */
+ cached
+ predicate defaultAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
+ localAdditionalTaintStep(nodeFrom, nodeTo)
+ or
+ any(AdditionalTaintStep a).step(nodeFrom, nodeTo)
+ }
+
+ /**
+ * Holds if taint can flow in one local step from `nodeFrom` to `nodeTo` excluding
+ * local data flow steps. That is, `nodeFrom` and `nodeTo` are likely to represent
+ * different objects.
+ */
+ cached
+ predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
+ concatStep(nodeFrom, nodeTo)
+ or
+ subscriptStep(nodeFrom, nodeTo)
+ or
+ stringManipulation(nodeFrom, nodeTo)
+ or
+ containerStep(nodeFrom, nodeTo)
+ or
+ copyStep(nodeFrom, nodeTo)
+ or
+ forStep(nodeFrom, nodeTo)
+ or
+ unpackingAssignmentStep(nodeFrom, nodeTo)
+ }
}
-/**
- * Holds if taint can flow in one local step from `nodeFrom` to `nodeTo` excluding
- * local data flow steps. That is, `nodeFrom` and `nodeTo` are likely to represent
- * different objects.
- */
-predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
- concatStep(nodeFrom, nodeTo)
- or
- subscriptStep(nodeFrom, nodeTo)
- or
- stringManipulation(nodeFrom, nodeTo)
- or
- containerStep(nodeFrom, nodeTo)
- or
- copyStep(nodeFrom, nodeTo)
- or
- forStep(nodeFrom, nodeTo)
- or
- unpackingAssignmentStep(nodeFrom, nodeTo)
-}
+import Cached
/**
* Holds if taint can flow from `nodeFrom` to `nodeTo` with a step related to concatenation.
diff --git a/python/ql/src/semmle/python/security/internal/SensitiveDataHeuristics.qll b/python/ql/src/semmle/python/security/internal/SensitiveDataHeuristics.qll
index ddf95b1b534..589c37120b9 100644
--- a/python/ql/src/semmle/python/security/internal/SensitiveDataHeuristics.qll
+++ b/python/ql/src/semmle/python/security/internal/SensitiveDataHeuristics.qll
@@ -58,7 +58,8 @@ module HeuristicNames {
*/
string maybeAccountInfo() {
result = "(?is).*acc(ou)?nt.*" or
- result = "(?is).*(puid|username|userid).*"
+ result = "(?is).*(puid|username|userid).*" or
+ result = "(?s).*([uU]|^|_|[a-z](?=U))([uU][iI][dD]).*"
}
/**
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-730/RegexInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-730/RegexInjection.expected
new file mode 100644
index 00000000000..97ed0d1bdfa
--- /dev/null
+++ b/python/ql/test/experimental/query-tests/Security/CWE-730/RegexInjection.expected
@@ -0,0 +1,27 @@
+edges
+| re_bad.py:13:22:13:28 | ControlFlowNode for request | re_bad.py:13:22:13:33 | ControlFlowNode for Attribute |
+| re_bad.py:13:22:13:33 | ControlFlowNode for Attribute | re_bad.py:13:22:13:44 | ControlFlowNode for Subscript |
+| re_bad.py:13:22:13:44 | ControlFlowNode for Subscript | re_bad.py:14:15:14:28 | ControlFlowNode for unsafe_pattern |
+| re_bad.py:24:22:24:28 | ControlFlowNode for request | re_bad.py:24:22:24:33 | ControlFlowNode for Attribute |
+| re_bad.py:24:22:24:33 | ControlFlowNode for Attribute | re_bad.py:24:22:24:44 | ControlFlowNode for Subscript |
+| re_bad.py:24:22:24:44 | ControlFlowNode for Subscript | re_bad.py:25:35:25:48 | ControlFlowNode for unsafe_pattern |
+| re_bad.py:36:22:36:28 | ControlFlowNode for request | re_bad.py:36:22:36:33 | ControlFlowNode for Attribute |
+| re_bad.py:36:22:36:33 | ControlFlowNode for Attribute | re_bad.py:36:22:36:44 | ControlFlowNode for Subscript |
+| re_bad.py:36:22:36:44 | ControlFlowNode for Subscript | re_bad.py:37:16:37:29 | ControlFlowNode for unsafe_pattern |
+nodes
+| re_bad.py:13:22:13:28 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| re_bad.py:13:22:13:33 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| re_bad.py:13:22:13:44 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| re_bad.py:14:15:14:28 | ControlFlowNode for unsafe_pattern | semmle.label | ControlFlowNode for unsafe_pattern |
+| re_bad.py:24:22:24:28 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| re_bad.py:24:22:24:33 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| re_bad.py:24:22:24:44 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| re_bad.py:25:35:25:48 | ControlFlowNode for unsafe_pattern | semmle.label | ControlFlowNode for unsafe_pattern |
+| re_bad.py:36:22:36:28 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| re_bad.py:36:22:36:33 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| re_bad.py:36:22:36:44 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| re_bad.py:37:16:37:29 | ControlFlowNode for unsafe_pattern | semmle.label | ControlFlowNode for unsafe_pattern |
+#select
+| re_bad.py:14:15:14:28 | ControlFlowNode for unsafe_pattern | re_bad.py:13:22:13:28 | ControlFlowNode for request | re_bad.py:14:15:14:28 | ControlFlowNode for unsafe_pattern | $@ regular expression is constructed from a $@ and executed by $@. | re_bad.py:14:15:14:28 | ControlFlowNode for unsafe_pattern | This | re_bad.py:13:22:13:28 | ControlFlowNode for request | user-provided value | re_bad.py:14:5:14:13 | Attribute | re.search |
+| re_bad.py:25:35:25:48 | ControlFlowNode for unsafe_pattern | re_bad.py:24:22:24:28 | ControlFlowNode for request | re_bad.py:25:35:25:48 | ControlFlowNode for unsafe_pattern | $@ regular expression is constructed from a $@ and executed by $@. | re_bad.py:25:35:25:48 | ControlFlowNode for unsafe_pattern | This | re_bad.py:24:22:24:28 | ControlFlowNode for request | user-provided value | re_bad.py:26:5:26:27 | Attribute | re.search |
+| re_bad.py:37:16:37:29 | ControlFlowNode for unsafe_pattern | re_bad.py:36:22:36:28 | ControlFlowNode for request | re_bad.py:37:16:37:29 | ControlFlowNode for unsafe_pattern | $@ regular expression is constructed from a $@ and executed by $@. | re_bad.py:37:16:37:29 | ControlFlowNode for unsafe_pattern | This | re_bad.py:36:22:36:28 | ControlFlowNode for request | user-provided value | re_bad.py:37:5:37:37 | Attribute | re.search |
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-730/RegexInjection.qlref b/python/ql/test/experimental/query-tests/Security/CWE-730/RegexInjection.qlref
new file mode 100644
index 00000000000..c0c506c4707
--- /dev/null
+++ b/python/ql/test/experimental/query-tests/Security/CWE-730/RegexInjection.qlref
@@ -0,0 +1 @@
+experimental/Security/CWE-730/RegexInjection.ql
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-730/re_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-730/re_bad.py
new file mode 100644
index 00000000000..622eaf199f6
--- /dev/null
+++ b/python/ql/test/experimental/query-tests/Security/CWE-730/re_bad.py
@@ -0,0 +1,40 @@
+from flask import request, Flask
+import re
+
+app = Flask(__name__)
+
+
+@app.route("/direct")
+def direct():
+ """
+ A RemoteFlowSource is used directly as re.search's pattern
+ """
+
+ unsafe_pattern = request.args["pattern"]
+ re.search(unsafe_pattern, "")
+
+
+@app.route("/compile")
+def compile():
+ """
+ A RemoteFlowSource is used directly as re.compile's pattern
+ which also executes .search()
+ """
+
+ unsafe_pattern = request.args["pattern"]
+ compiled_pattern = re.compile(unsafe_pattern)
+ compiled_pattern.search("")
+
+
+@app.route("/compile_direct")
+def compile_direct():
+ """
+ A RemoteFlowSource is used directly as re.compile's pattern
+ which also executes .search() in the same line
+ """
+
+ unsafe_pattern = request.args["pattern"]
+ re.compile(unsafe_pattern).search("")
+
+# if __name__ == "__main__":
+# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-730/re_good.py b/python/ql/test/experimental/query-tests/Security/CWE-730/re_good.py
new file mode 100644
index 00000000000..6dc58b87f85
--- /dev/null
+++ b/python/ql/test/experimental/query-tests/Security/CWE-730/re_good.py
@@ -0,0 +1,45 @@
+from flask import request, Flask
+import re
+
+app = Flask(__name__)
+
+
+@app.route("/direct")
+def direct():
+ """
+ A RemoteFlowSource is escaped by re.escape and then used as
+ re'search pattern
+ """
+
+ unsafe_pattern = request.args['pattern']
+ safe_pattern = re.escape(unsafe_pattern)
+ re.search(safe_pattern, "")
+
+
+@app.route("/compile")
+def compile():
+ """
+ A RemoteFlowSource is escaped by re.escape and used as re.compile's
+ pattern which also executes .search()
+ """
+
+ unsafe_pattern = request.args['pattern']
+ safe_pattern = re.escape(unsafe_pattern)
+ compiled_pattern = re.compile(safe_pattern)
+ compiled_pattern.search("")
+
+
+@app.route("/compile_direct")
+def compile_direct():
+ """
+ A RemoteFlowSource is escaped by re.escape and then used as re.compile's
+ pattern which also executes .search() in the same line
+ """
+
+ unsafe_pattern = request.args['pattern']
+ safe_pattern = re.escape(unsafe_pattern)
+ re.compile(safe_pattern).search("")
+
+
+# if __name__ == "__main__":
+# app.run(debug=True)