From fda4ab155ad95e6176a26ff1c67a21682d7b626d Mon Sep 17 00:00:00 2001
From: Grzegorz Golawski
Date: Sun, 23 Feb 2020 20:03:41 +0100
Subject: [PATCH 0001/1298] CodeQL query to detect open Spring Boot actuator
endpoints
---
.../CWE/CWE-016/SpringBootActuators.java | 22 +++
.../CWE/CWE-016/SpringBootActuators.qhelp | 36 +++++
.../CWE/CWE-016/SpringBootActuators.ql | 18 +++
.../CWE/CWE-016/SpringBootActuators.qll | 143 ++++++++++++++++++
.../security/CWE-016/SpringBootActuators.java | 40 +++++
.../CWE-016/SpringBootActuators.qlref | 1 +
6 files changed, 260 insertions(+)
create mode 100644 java/ql/src/Security/CWE/CWE-016/SpringBootActuators.java
create mode 100644 java/ql/src/Security/CWE/CWE-016/SpringBootActuators.qhelp
create mode 100644 java/ql/src/Security/CWE/CWE-016/SpringBootActuators.ql
create mode 100644 java/ql/src/Security/CWE/CWE-016/SpringBootActuators.qll
create mode 100644 java/ql/test/query-tests/security/CWE-016/SpringBootActuators.java
create mode 100644 java/ql/test/query-tests/security/CWE-016/SpringBootActuators.qlref
diff --git a/java/ql/src/Security/CWE/CWE-016/SpringBootActuators.java b/java/ql/src/Security/CWE/CWE-016/SpringBootActuators.java
new file mode 100644
index 00000000000..63b9aadbc10
--- /dev/null
+++ b/java/ql/src/Security/CWE/CWE-016/SpringBootActuators.java
@@ -0,0 +1,22 @@
+@Configuration(proxyBeanMethods = false)
+public class ActuatorSecurity extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // BAD: Unauthenticated access to Spring Boot actuator endpoints is allowed
+ http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests((requests) ->
+ requests.anyRequest().permitAll());
+ }
+}
+
+@Configuration(proxyBeanMethods = false)
+public class ActuatorSecurity extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // GOOD: only users with ENDPOINT_ADMIN role are allowed to access the actuator endpoints
+ http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests((requests) ->
+ requests.anyRequest().hasRole("ENDPOINT_ADMIN"));
+ http.httpBasic();
+ }
+}
\ No newline at end of file
diff --git a/java/ql/src/Security/CWE/CWE-016/SpringBootActuators.qhelp b/java/ql/src/Security/CWE/CWE-016/SpringBootActuators.qhelp
new file mode 100644
index 00000000000..1e2fe651860
--- /dev/null
+++ b/java/ql/src/Security/CWE/CWE-016/SpringBootActuators.qhelp
@@ -0,0 +1,36 @@
+
+
+
+Spring Boot includes a number of additional features called actuators that let you monitor
+and interact with your web application. Exposing unprotected actuator endpoints via JXM or HTTP
+can, however, lead to information disclosure or even to remote code execution vulnerability.
+
+
+
+Since actuator endpoints may contain sensitive information, careful consideration should be
+given about when to expose them. You should take care to secure exposed HTTP endpoints in the same
+way that you would any other sensitive URL. If Spring Security is present, endpoints are secured by
+default using Spring Security’s content-negotiation strategy. If you wish to configure custom
+security for HTTP endpoints, for example, only allow users with a certain role to access them,
+Spring Boot provides some convenient RequestMatcher objects that can be used in
+combination with Spring Security.
+
+
+
+In the first example, the custom security configuration allows unauthenticated access to all
+actuator endpoints. This may lead to sensitive information disclosure and should be avoided.
+In the second example, only users with ENDPOINT_ADMIN role are allowed to access
+the actuator endpoints.
+
+
+
+
+
+
+Spring Boot documentation:
+Actuators.
+
+
+
diff --git a/java/ql/src/Security/CWE/CWE-016/SpringBootActuators.ql b/java/ql/src/Security/CWE/CWE-016/SpringBootActuators.ql
new file mode 100644
index 00000000000..85daa77cc56
--- /dev/null
+++ b/java/ql/src/Security/CWE/CWE-016/SpringBootActuators.ql
@@ -0,0 +1,18 @@
+/**
+ * @name Exposed Spring Boot actuators
+ * @description Exposing Spring Boot actuators may lead to internal application's information leak
+ * or even to remote code execution.
+ * @kind problem
+ * @problem.severity error
+ * @precision high
+ * @id java/spring-boot-exposed-actuators
+ * @tags security
+ * external/cwe/cwe-16
+ */
+
+import java
+import SpringBootActuators
+
+from PermitAllCall permitAllCall
+where permitAllCall.permitsSpringBootActuators()
+select permitAllCall, "Unauthenticated access to Spring Boot actuator is allowed."
diff --git a/java/ql/src/Security/CWE/CWE-016/SpringBootActuators.qll b/java/ql/src/Security/CWE/CWE-016/SpringBootActuators.qll
new file mode 100644
index 00000000000..36223e4b6e6
--- /dev/null
+++ b/java/ql/src/Security/CWE/CWE-016/SpringBootActuators.qll
@@ -0,0 +1,143 @@
+import java
+
+/** The class `org.springframework.security.config.annotation.web.builders.HttpSecurity`. */
+class TypeHttpSecurity extends Class {
+ TypeHttpSecurity() {
+ this
+ .hasQualifiedName("org.springframework.security.config.annotation.web.builders",
+ "HttpSecurity")
+ }
+}
+
+/**
+ * The class
+ * `org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer`.
+ */
+class TypeAuthorizedUrl extends Class {
+ TypeAuthorizedUrl() {
+ this
+ .hasQualifiedName("org.springframework.security.config.annotation.web.configurers",
+ "ExpressionUrlAuthorizationConfigurer$AuthorizedUrl<>")
+ }
+}
+
+/**
+ * The class
+ * `org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry`.
+ */
+class TypeAbstractRequestMatcherRegistry extends Class {
+ TypeAbstractRequestMatcherRegistry() {
+ this
+ .hasQualifiedName("org.springframework.security.config.annotation.web",
+ "AbstractRequestMatcherRegistry>")
+ }
+}
+
+/**
+ * The class
+ * `org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest.EndpointRequestMatcher`.
+ */
+class TypeEndpointRequestMatcher extends Class {
+ TypeEndpointRequestMatcher() {
+ this
+ .hasQualifiedName("org.springframework.boot.actuate.autoconfigure.security.servlet",
+ "EndpointRequest$EndpointRequestMatcher")
+ }
+}
+
+/**
+ * A call to `HttpSecurity.requestMatcher` method with argument of type
+ * `EndpointRequestMatcher`.
+ */
+class RequestMatcherCall extends MethodAccess {
+ RequestMatcherCall() {
+ getMethod().hasName("requestMatcher") and
+ getMethod().getDeclaringType() instanceof TypeHttpSecurity and
+ getArgument(0).getType() instanceof TypeEndpointRequestMatcher
+ }
+}
+
+/**
+ * A call to `HttpSecurity.requestMatchers` method with lambda argument resolving to
+ * `EndpointRequestMatcher` type.
+ */
+class RequestMatchersCall extends MethodAccess {
+ RequestMatchersCall() {
+ getMethod().hasName("requestMatchers") and
+ getMethod().getDeclaringType() instanceof TypeHttpSecurity and
+ getArgument(0).(LambdaExpr).getExprBody().getType() instanceof TypeEndpointRequestMatcher
+ }
+}
+
+/** A call to `HttpSecurity.authorizeRequests` method. */
+class AuthorizeRequestsCall extends MethodAccess {
+ AuthorizeRequestsCall() {
+ getMethod().hasName("authorizeRequests") and
+ getMethod().getDeclaringType() instanceof TypeHttpSecurity
+ }
+}
+
+/** A call to `AuthorizedUrl.permitAll` method. */
+class PermitAllCall extends MethodAccess {
+ PermitAllCall() {
+ getMethod().hasName("permitAll") and
+ getMethod().getDeclaringType() instanceof TypeAuthorizedUrl
+ }
+
+ /** Holds if `permitAll` is called on request(s) mapped to actuator endpoint(s). */
+ predicate permitsSpringBootActuators() {
+ exists(
+ RequestMatcherCall requestMatcherCall, RequestMatchersCall requestMatchersCall,
+ RegistryRequestMatchersCall registryRequestMatchersCall,
+ AuthorizeRequestsCall authorizeRequestsCall, AnyRequestCall anyRequestCall
+ |
+ // .requestMatcher(EndpointRequest).authorizeRequests([...]).[...]
+ authorizeRequestsCall.getQualifier() = requestMatcherCall
+ or
+ // .requestMatchers(matcher -> EndpointRequest).authorizeRequests([...]).[...]
+ authorizeRequestsCall.getQualifier() = requestMatchersCall
+ or
+ // http.authorizeRequests([...]).[...]
+ authorizeRequestsCall.getQualifier() instanceof VarAccess
+ |
+ // [...].authorizeRequests(r -> r.anyRequest().permitAll()) or
+ // [...].authorizeRequests(r -> r.requestMatchers(EndpointRequest).permitAll())
+ authorizeRequestsCall.getArgument(0).(LambdaExpr).getExprBody() = this and
+ (
+ this.getQualifier() = anyRequestCall or
+ this.getQualifier() = registryRequestMatchersCall
+ )
+ or
+ // [...].authorizeRequests().requestMatchers(EndpointRequest).permitAll() or
+ // [...].authorizeRequests().anyRequest().permitAll()
+ authorizeRequestsCall.getNumArgument() = 0 and
+ (
+ registryRequestMatchersCall.getQualifier() = authorizeRequestsCall and
+ this.getQualifier() = registryRequestMatchersCall
+ )
+ or
+ anyRequestCall.getQualifier() = authorizeRequestsCall and
+ this.getQualifier() = anyRequestCall
+ )
+ }
+}
+
+/** A call to `AbstractRequestMatcherRegistry.anyRequest` method. */
+class AnyRequestCall extends MethodAccess {
+ AnyRequestCall() {
+ getMethod().hasName("anyRequest") and
+ getMethod().getDeclaringType() instanceof TypeAbstractRequestMatcherRegistry
+ }
+}
+
+/**
+ * A call to `AbstractRequestMatcherRegistry.requestMatchers` method with an argument of type
+ * `EndpointRequestMatcher`.
+ */
+class RegistryRequestMatchersCall extends MethodAccess {
+ RegistryRequestMatchersCall() {
+ getMethod().hasName("requestMatchers") and
+ getMethod().getDeclaringType() instanceof TypeAbstractRequestMatcherRegistry and
+ getAnArgument().getType() instanceof TypeEndpointRequestMatcher
+ }
+}
diff --git a/java/ql/test/query-tests/security/CWE-016/SpringBootActuators.java b/java/ql/test/query-tests/security/CWE-016/SpringBootActuators.java
new file mode 100644
index 00000000000..920a1ff05c0
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-016/SpringBootActuators.java
@@ -0,0 +1,40 @@
+import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+
+public class ActuatorSecurityConfig {
+ protected void configure(HttpSecurity http) throws Exception {
+ http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests(requests -> requests.anyRequest().permitAll());
+ }
+
+ protected void configure2(HttpSecurity http) throws Exception {
+ http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll();
+ }
+
+ protected void configure3(HttpSecurity http) throws Exception {
+ http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll();
+ }
+
+ protected void configure4(HttpSecurity http) throws Exception {
+ http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest().permitAll();
+ }
+
+ protected void configure5(HttpSecurity http) throws Exception {
+ http.authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll();
+ }
+
+ protected void configure6(HttpSecurity http) throws Exception {
+ http.authorizeRequests(requests -> requests.requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll());
+ }
+
+ protected void configure7(HttpSecurity http) throws Exception {
+ http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest().permitAll();
+ }
+
+ protected void configureOk1(HttpSecurity http) throws Exception {
+ http.requestMatcher(EndpointRequest.toAnyEndpoint());
+ }
+
+ protected void configureOk2(HttpSecurity http) throws Exception {
+ http.requestMatchers().requestMatchers(EndpointRequest.toAnyEndpoint());
+ }
+}
diff --git a/java/ql/test/query-tests/security/CWE-016/SpringBootActuators.qlref b/java/ql/test/query-tests/security/CWE-016/SpringBootActuators.qlref
new file mode 100644
index 00000000000..abd5f2a7599
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-016/SpringBootActuators.qlref
@@ -0,0 +1 @@
+Security/CWE/CWE-016/SpringBootActuators.ql
From 84875d70ffc9ba0f8040814d7a5729820c700812 Mon Sep 17 00:00:00 2001
From: Rebecca Valentine
Date: Wed, 26 Feb 2020 21:42:52 -0800
Subject: [PATCH 0002/1298] Adds preliminary modernization
This will overlapp with/depend on changes to CallArgs and ObjectAPI that are already in the WrongNamedArgumentInCall PR
---
python/ql/src/Expressions/WrongNumberArgumentsInCall.ql | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql b/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql
index 9f636213a34..4101bd3a854 100644
--- a/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql
+++ b/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql
@@ -14,15 +14,15 @@
import python
import CallArgs
-from Call call, FunctionObject func, string too, string should, int limit
+from Call call, FunctionValue func, string too, string should, int limit
where
(
- too_many_args_objectapi(call, func, limit) and too = "too many arguments" and should = "no more than "
+ too_many_args(call, func, limit) and too = "too many arguments" and should = "no more than "
or
- too_few_args_objectapi(call, func, limit) and too = "too few arguments" and should = "no fewer than "
+ too_few_args(call, func, limit) and too = "too few arguments" and should = "no fewer than "
) and
not func.isAbstract() and
-not exists(FunctionObject overridden | func.overrides(overridden) and correct_args_if_called_as_method_objectapi(call, overridden))
+not exists(FunctionValue overridden | func.overrides(overridden) and correct_args_if_called_as_method(call, overridden))
/* The semantics of `__new__` can be a bit subtle, so we simply exclude `__new__` methods */
and not func.getName() = "__new__"
From dfb42ecf4241328808640aff9d619adfff3f998c Mon Sep 17 00:00:00 2001
From: luchua-bc
Date: Wed, 18 Mar 2020 15:55:56 -0400
Subject: [PATCH 0003/1298] Address sensitive info logging
---
.../CWE-532/SensitiveInfoLog.java | 18 ++++
.../CWE-532/SensitiveInfoLog.qhelp | 29 +++++++
.../experimental/CWE-532/SensitiveInfoLog.ql | 83 +++++++++++++++++++
3 files changed, 130 insertions(+)
create mode 100644 java/ql/src/experimental/CWE-532/SensitiveInfoLog.java
create mode 100644 java/ql/src/experimental/CWE-532/SensitiveInfoLog.qhelp
create mode 100644 java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql
diff --git a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.java b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.java
new file mode 100644
index 00000000000..b820e22346f
--- /dev/null
+++ b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.java
@@ -0,0 +1,18 @@
+public static void main(String[] args) {
+ {
+ private static final Logger logger = LogManager.getLogger(SensitiveInfoLog.class);
+
+ String password = "Pass@0rd";
+
+ // BAD: user password is written to debug log
+ logger.debug("User password is "+password);
+ }
+
+ {
+ private static final Logger logger = LogManager.getLogger(SensitiveInfoLog.class);
+
+ String password = "Pass@0rd";
+
+ // GOOD: user password is never written to debug log
+ }
+}
diff --git a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.qhelp b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.qhelp
new file mode 100644
index 00000000000..5d2237e46a7
--- /dev/null
+++ b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.qhelp
@@ -0,0 +1,29 @@
+
+
+
+
+Information written to log files can be of a sensitive nature and give valuable guidance to an attacker or expose sensitive user information. Third-party logging utilities like Log4J and SLF4J are widely used in Java projects. When sensitive information are written to logs without properly set logging levels, it is accessible to potential attackers who gains access to the
+file storage.
+
+
+
+Do not write secrets into the log files and enforce proper logging level control.
+
+
+
+The following example shows two ways of logging sensitive information. In the 'BAD' case,
+the credentials are simply written to a debug log. In the 'GOOD' case, the credentials are never written to debug logs.
+
+
+
+
+
+OWASP Logging Guide
+
+
+CWE 532
+
+
+
diff --git a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql
new file mode 100644
index 00000000000..4648eb3e5fd
--- /dev/null
+++ b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql
@@ -0,0 +1,83 @@
+/**
+ * @id java/sensitiveinfo-in-logfile
+ * @name Insertion of sensitive information into log files
+ * @description Writting sensitive information to log files can give valuable guidance to an attacker or expose sensitive user information.
+ * @kind problem
+ * @tags security
+ * external/cwe-532
+ */
+
+import java
+import semmle.code.java.dataflow.TaintTracking
+import DataFlow
+import PathGraph
+
+/** Class of popular logging utilities **/
+class LoggerType extends RefType {
+ LoggerType() {
+ this.hasQualifiedName("org.apache.log4j", "Category") or //Log4J
+ this.hasQualifiedName("org.slf4j", "Logger") //SLF4j
+ }
+}
+
+/** Concatenated string with a variable that keeps sensitive information judging by its name **/
+class CredentialExpr extends Expr {
+ CredentialExpr() {
+ exists (Variable v | this.(AddExpr).getAnOperand() = v.getAnAccess() | v.getName().regexpMatch(getACredentialRegex()))
+ }
+}
+
+/** Source in concatenated string or variable itself **/
+class CredentialSource extends DataFlow::ExprNode {
+ CredentialSource() {
+ exists (
+ Variable v | this.asExpr() = v.getAnAccess() | v.getName().regexpMatch(getACredentialRegex())
+ ) or
+ exists (
+ this.asExpr().(AddExpr).getAnOperand().(CredentialExpr)
+ ) or
+ exists (
+ this.asExpr().(CredentialExpr)
+ )
+ }
+}
+
+/**
+ * Gets a regular expression for matching names of variables that indicate the value being held is a credential.
+ */
+
+private string getACredentialRegex() {
+ result = "(?i).*pass(wd|word|code|phrase)(?!.*question).*" or
+ result = "(?i).*(uid|uuid|puid|username|userid|url).*"
+}
+
+class SensitiveLoggingSink extends DataFlow::ExprNode {
+ SensitiveLoggingSink() {
+ exists(MethodAccess ma |
+ ma.getMethod().getDeclaringType() instanceof LoggerType and
+ (
+ ma.getMethod().hasName("debug")
+ ) and
+ this.asExpr() = ma.getAnArgument()
+ )
+ }
+}
+
+class SensitiveLoggingConfig extends Configuration {
+ SensitiveLoggingConfig() {
+ this = "SensitiveLoggingConfig"
+ }
+
+ override predicate isSource(Node source) {
+ source instanceof CredentialSource
+ }
+
+ override predicate isSink(Node sink) {
+ sink instanceof SensitiveLoggingSink
+ }
+}
+
+from Node source, Node sink, SensitiveLoggingConfig conf, MethodAccess ma
+where conf.hasFlow(source, sink) and ma.getAnArgument() = source.asExpr() and ma.getAnArgument() = sink.asExpr()
+select "Outputting sensitive information $@ in method call $@.", source, ma, "to log files"
+
From d9327705d200c22ed1863e00141c942a8a6304d0 Mon Sep 17 00:00:00 2001
From: luchua-bc
Date: Wed, 18 Mar 2020 16:48:31 -0400
Subject: [PATCH 0004/1298] Fix the issue of mixed tabs and spaces
---
.../CWE-532/SensitiveInfoLog.java | 24 +++++++++----------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.java b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.java
index b820e22346f..e1f7354b912 100644
--- a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.java
+++ b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.java
@@ -1,18 +1,18 @@
public static void main(String[] args) {
- {
- private static final Logger logger = LogManager.getLogger(SensitiveInfoLog.class);
-
- String password = "Pass@0rd";
+ {
+ private static final Logger logger = LogManager.getLogger(SensitiveInfoLog.class);
- // BAD: user password is written to debug log
- logger.debug("User password is "+password);
- }
+ String password = "Pass@0rd";
+
+ // BAD: user password is written to debug log
+ logger.debug("User password is "+password);
+ }
- {
- private static final Logger logger = LogManager.getLogger(SensitiveInfoLog.class);
+ {
+ private static final Logger logger = LogManager.getLogger(SensitiveInfoLog.class);
- String password = "Pass@0rd";
+ String password = "Pass@0rd";
- // GOOD: user password is never written to debug log
- }
+ // GOOD: user password is never written to debug log
+ }
}
From 22381f3ee616729836f79f60cf938a8a546b181e Mon Sep 17 00:00:00 2001
From: Mathias Vorreiter Pedersen
Date: Tue, 24 Mar 2020 22:01:56 +0100
Subject: [PATCH 0005/1298] C++: Demonstrate amount of field flow already
present
---
.../cpp/ir/dataflow/internal/DataFlowUtil.qll | 1 +
.../dataflow/fields/ir-flow.expected | 31 +++++++++++++
.../library-tests/dataflow/fields/ir-flow.ql | 46 +++++++++++++++++++
3 files changed, 78 insertions(+)
create mode 100644 cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
create mode 100644 cpp/ql/test/library-tests/dataflow/fields/ir-flow.ql
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
index e19912a63ee..c89d7312813 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
@@ -63,6 +63,7 @@ class Node extends TIRDataFlowNode {
*/
Variable asVariable() { result = this.(VariableNode).getVariable() }
+
/**
* DEPRECATED: See UninitializedNode.
*
diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
new file mode 100644
index 00000000000..2503be80b00
--- /dev/null
+++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
@@ -0,0 +1,31 @@
+edges
+| aliasing.cpp:37:13:37:22 | call to user_input : void | aliasing.cpp:38:11:38:12 | m1 |
+| aliasing.cpp:42:11:42:20 | call to user_input : void | aliasing.cpp:43:13:43:14 | m1 |
+| aliasing.cpp:79:11:79:20 | call to user_input : void | aliasing.cpp:80:12:80:13 | m1 |
+| aliasing.cpp:86:10:86:19 | call to user_input : void | aliasing.cpp:87:12:87:13 | m1 |
+| aliasing.cpp:92:12:92:21 | call to user_input : void | aliasing.cpp:93:12:93:13 | m1 |
+| struct_init.c:20:20:20:29 | call to user_input : void | struct_init.c:22:11:22:11 | a |
+| struct_init.c:27:7:27:16 | call to user_input : void | struct_init.c:31:23:31:23 | a |
+nodes
+| aliasing.cpp:37:13:37:22 | call to user_input : void | semmle.label | call to user_input : void |
+| aliasing.cpp:38:11:38:12 | m1 | semmle.label | m1 |
+| aliasing.cpp:42:11:42:20 | call to user_input : void | semmle.label | call to user_input : void |
+| aliasing.cpp:43:13:43:14 | m1 | semmle.label | m1 |
+| aliasing.cpp:79:11:79:20 | call to user_input : void | semmle.label | call to user_input : void |
+| aliasing.cpp:80:12:80:13 | m1 | semmle.label | m1 |
+| aliasing.cpp:86:10:86:19 | call to user_input : void | semmle.label | call to user_input : void |
+| aliasing.cpp:87:12:87:13 | m1 | semmle.label | m1 |
+| aliasing.cpp:92:12:92:21 | call to user_input : void | semmle.label | call to user_input : void |
+| aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 |
+| struct_init.c:20:20:20:29 | call to user_input : void | semmle.label | call to user_input : void |
+| struct_init.c:22:11:22:11 | a | semmle.label | a |
+| struct_init.c:27:7:27:16 | call to user_input : void | semmle.label | call to user_input : void |
+| struct_init.c:31:23:31:23 | a | semmle.label | a |
+#select
+| aliasing.cpp:38:11:38:12 | m1 | aliasing.cpp:37:13:37:22 | call to user_input : void | aliasing.cpp:38:11:38:12 | m1 | m1 flows from $@ | aliasing.cpp:37:13:37:22 | call to user_input : void | call to user_input : void |
+| aliasing.cpp:43:13:43:14 | m1 | aliasing.cpp:42:11:42:20 | call to user_input : void | aliasing.cpp:43:13:43:14 | m1 | m1 flows from $@ | aliasing.cpp:42:11:42:20 | call to user_input : void | call to user_input : void |
+| aliasing.cpp:80:12:80:13 | m1 | aliasing.cpp:79:11:79:20 | call to user_input : void | aliasing.cpp:80:12:80:13 | m1 | m1 flows from $@ | aliasing.cpp:79:11:79:20 | call to user_input : void | call to user_input : void |
+| aliasing.cpp:87:12:87:13 | m1 | aliasing.cpp:86:10:86:19 | call to user_input : void | aliasing.cpp:87:12:87:13 | m1 | m1 flows from $@ | aliasing.cpp:86:10:86:19 | call to user_input : void | call to user_input : void |
+| aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input : void | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input : void | call to user_input : void |
+| struct_init.c:22:11:22:11 | a | struct_init.c:20:20:20:29 | call to user_input : void | struct_init.c:22:11:22:11 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input : void | call to user_input : void |
+| struct_init.c:31:23:31:23 | a | struct_init.c:27:7:27:16 | call to user_input : void | struct_init.c:31:23:31:23 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input : void | call to user_input : void |
diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.ql b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.ql
new file mode 100644
index 00000000000..098c6b6bd27
--- /dev/null
+++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.ql
@@ -0,0 +1,46 @@
+/**
+ * @kind path-problem
+ */
+
+import semmle.code.cpp.ir.dataflow.DataFlow
+import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
+import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
+import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl
+import semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon
+import semmle.code.cpp.ir.IR
+import DataFlow::PathGraph
+import cpp
+
+class Conf extends DataFlow::Configuration {
+ Conf() { this = "FieldFlowConf" }
+
+ override predicate isSource(Node src) {
+ src.asExpr() instanceof NewExpr
+ or
+ src.asExpr().(Call).getTarget().hasName("user_input")
+ or
+ exists(FunctionCall fc |
+ fc.getAnArgument() = src.asDefiningArgument() and
+ fc.getTarget().hasName("argument_source")
+ )
+ }
+
+ override predicate isSink(Node sink) {
+ exists(Call c |
+ c.getTarget().hasName("sink") and
+ c.getAnArgument() = sink.asExpr()
+ )
+ }
+
+ override predicate isAdditionalFlowStep(Node a, Node b) {
+ b.asPartialDefinition() =
+ any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr())
+ .getQualifier()
+ or
+ b.asExpr().(AddressOfExpr).getOperand() = a.asExpr()
+ }
+}
+
+from DataFlow::PathNode src, DataFlow::PathNode sink, Conf conf
+where conf.hasFlowPath(src, sink)
+select sink, src, sink, sink + " flows from $@", src, src.toString()
From a5f08e1ea6c746e3340850c2b82617cf27f581b8 Mon Sep 17 00:00:00 2001
From: Mathias Vorreiter Pedersen
Date: Tue, 24 Mar 2020 22:07:50 +0100
Subject: [PATCH 0006/1298] C++: Split parameter node class into an explicit
and implicit version
---
.../cpp/ir/dataflow/internal/DataFlowUtil.qll | 30 ++++++++++++-------
1 file changed, 20 insertions(+), 10 deletions(-)
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
index c89d7312813..9373483051e 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
@@ -55,7 +55,7 @@ class Node extends TIRDataFlowNode {
Expr asDefiningArgument() { result = this.(DefinitionByReferenceNode).getArgument() }
/** Gets the parameter corresponding to this node, if any. */
- Parameter asParameter() { result = this.(ParameterNode).getParameter() }
+ Parameter asParameter() { result = this.(ExplicitParameterNode).getParameter() }
/**
* Gets the variable corresponding to this node, if any. This can be used for
@@ -143,27 +143,37 @@ class ExprNode extends InstructionNode {
override string toString() { result = this.asConvertedExpr().toString() }
}
-/**
- * The value of a parameter at function entry, viewed as a node in a data
- * flow graph.
- */
class ParameterNode extends InstructionNode {
- override InitializeParameterInstruction instr;
-
/**
* Holds if this node is the parameter of `c` at the specified (zero-based)
* position. The implicit `this` parameter is considered to have index `-1`.
*/
- predicate isParameterOf(Function f, int i) { f.getParameter(i) = instr.getParameter() }
+ predicate isParameterOf(Function f, int i) {
+ none()
+ }
+}
+
+/**
+ * The value of a parameter at function entry, viewed as a node in a data
+ * flow graph.
+ */
+private class ExplicitParameterNode extends ParameterNode {
+ override InitializeParameterInstruction instr;
+
+ override predicate isParameterOf(Function f, int i) { f.getParameter(i) = instr.getParameter() }
Parameter getParameter() { result = instr.getParameter() }
override string toString() { result = instr.getParameter().toString() }
}
-private class ThisParameterNode extends InstructionNode {
+private class ThisParameterNode extends ParameterNode {
override InitializeThisInstruction instr;
+ override predicate isParameterOf(Function f, int i) {
+ i = -1 and instr.getEnclosingFunction() = f
+ }
+
override string toString() { result = "this" }
}
@@ -295,7 +305,7 @@ ExprNode convertedExprNode(Expr e) { result.getExpr() = e }
/**
* Gets the `Node` corresponding to the value of `p` at function entry.
*/
-ParameterNode parameterNode(Parameter p) { result.getParameter() = p }
+ExplicitParameterNode parameterNode(Parameter p) { result.getParameter() = p }
/** Gets the `VariableNode` corresponding to the variable `v`. */
VariableNode variableNode(Variable v) { result.getVariable() = v }
From 077c282cd3e5dc2d9838d92d178f5f16a32a87bc Mon Sep 17 00:00:00 2001
From: Mathias Vorreiter Pedersen
Date: Tue, 24 Mar 2020 22:11:29 +0100
Subject: [PATCH 0007/1298] C++: Add field flow and accept tests
---
.../ir/dataflow/internal/DataFlowPrivate.qll | 16 ++++-
.../cpp/ir/dataflow/internal/DataFlowUtil.qll | 67 +++++++++++++++----
.../dataflow/fields/ir-flow.expected | 60 +++++++++++++++++
3 files changed, 128 insertions(+), 15 deletions(-)
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
index 83e5d5eb06b..861a09f144a 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
@@ -131,7 +131,14 @@ private class ArrayContent extends Content, TArrayContent {
* value of `node1`.
*/
predicate storeStep(Node node1, Content f, PostUpdateNode node2) {
- none() // stub implementation
+ exists(FieldAddressInstruction fa |
+ exists(StoreInstruction store |
+ node1.asInstruction() = store and
+ store.getDestinationAddress() = fa
+ ) and
+ node2.getPreUpdateNode().asInstruction() = fa.getObjectAddress() and
+ f.(FieldContent).getField() = fa.getField()
+ )
}
/**
@@ -140,7 +147,12 @@ predicate storeStep(Node node1, Content f, PostUpdateNode node2) {
* `node2`.
*/
predicate readStep(Node node1, Content f, Node node2) {
- none() // stub implementation
+ exists(FieldAddressInstruction fa, LoadInstruction load |
+ load.getSourceAddress() = fa and
+ node1.asInstruction() = fa.getObjectAddress() and
+ fa.getField() = f.(FieldContent).getField() and
+ load = node2.asInstruction()
+ )
}
/**
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
index 9373483051e..2b88cc7ade1 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
@@ -63,6 +63,9 @@ class Node extends TIRDataFlowNode {
*/
Variable asVariable() { result = this.(VariableNode).getVariable() }
+ Expr asPartialDefinition() {
+ result = this.(PartialDefinitionNode).getInstruction().getUnconvertedResultExpression()
+ }
/**
* DEPRECATED: See UninitializedNode.
@@ -213,6 +216,19 @@ abstract class PostUpdateNode extends InstructionNode {
* Gets the node before the state update.
*/
abstract Node getPreUpdateNode();
+
+ override string toString() { result = getPreUpdateNode().toString() + " [post update]" }
+}
+
+abstract class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { }
+
+class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
+ override StoreInstruction instr;
+ FieldAddressInstruction field;
+
+ ExplicitFieldStoreQualifierNode() { field = instr.getDestinationAddress() }
+
+ override Node getPreUpdateNode() { result.asInstruction() = field.getObjectAddress() }
}
/**
@@ -225,24 +241,24 @@ abstract class PostUpdateNode extends InstructionNode {
* returned. This node will have its `getArgument()` equal to `&x` and its
* `getVariableAccess()` equal to `x`.
*/
-class DefinitionByReferenceNode extends InstructionNode {
+class DefinitionByReferenceNode extends PartialDefinitionNode {
override WriteSideEffectInstruction instr;
+ CallInstruction call;
+
+ DefinitionByReferenceNode() { call = instr.getPrimaryInstruction() }
+
+ override Node getPreUpdateNode() {
+ result.asInstruction() = call.getPositionalArgument(instr.getIndex())
+ or
+ result.asInstruction() = call.getThisArgument() and
+ instr.getIndex() = -1
+ }
/** Gets the argument corresponding to this node. */
Expr getArgument() {
- result =
- instr
- .getPrimaryInstruction()
- .(CallInstruction)
- .getPositionalArgument(instr.getIndex())
- .getUnconvertedResultExpression()
+ result = call.getPositionalArgument(instr.getIndex()).getUnconvertedResultExpression()
or
- result =
- instr
- .getPrimaryInstruction()
- .(CallInstruction)
- .getThisArgument()
- .getUnconvertedResultExpression() and
+ result = call.getThisArgument().getUnconvertedResultExpression() and
instr.getIndex() = -1
}
@@ -250,6 +266,24 @@ class DefinitionByReferenceNode extends InstructionNode {
Parameter getParameter() {
exists(CallInstruction ci | result = ci.getStaticCallTarget().getParameter(instr.getIndex()))
}
+
+ override string toString() { result = "ref arg " + getPreUpdateNode().toString() }
+}
+
+class PositionalArgumentWithoutWriteSideEffectNode extends PartialDefinitionNode {
+ override CallInstruction instr;
+ PositionalArgumentOperand op;
+
+ PositionalArgumentWithoutWriteSideEffectNode() {
+ instr.getAnOperand() = op and
+ not exists(WriteSideEffectInstruction write |
+ write.getIndex() = op.getIndex() and write.getPrimaryInstruction() = instr
+ )
+ }
+
+ override Node getPreUpdateNode() { result.asInstruction() = op.getDef() }
+
+ override string toString() { result = "no change to " + op.toString() }
}
/**
@@ -332,6 +366,13 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr
*/
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction())
+ or
+ exists(ChiInstruction chi, LoadInstruction load |
+ chi.getPartial() = nodeFrom.(PartialDefinitionNode).getInstruction() and
+ // TODO: This can probably be getSourceValue() after #3112 is merged
+ load.getSourceValueOperand().getAnyDef() = chi and
+ nodeTo.asInstruction() = load.getSourceAddress().(FieldAddressInstruction).getObjectAddress()
+ )
}
private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction iTo) {
diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
index 2503be80b00..c66255c7338 100644
--- a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
+++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
@@ -1,27 +1,87 @@
edges
+| A.cpp:126:5:126:5 | ref arg b [c] : void | A.cpp:131:8:131:8 | ref arg b [c] : void |
+| A.cpp:126:12:126:18 | new : void | A.cpp:126:5:126:5 | ref arg b [c] : void |
+| A.cpp:131:8:131:8 | ref arg b [c] : void | A.cpp:132:10:132:10 | b [c] : void |
+| A.cpp:132:10:132:10 | b [c] : void | A.cpp:132:13:132:13 | c |
+| A.cpp:132:10:132:10 | b [c] : void | A.cpp:132:13:132:13 | c : void |
+| A.cpp:132:13:132:13 | c : void | A.cpp:132:10:132:13 | (void *)... |
+| aliasing.cpp:9:3:9:22 | s [post update] : void | aliasing.cpp:9:3:9:22 | s [post update] [m1] : void |
+| aliasing.cpp:9:3:9:22 | s [post update] [m1] : void | aliasing.cpp:25:17:25:19 | ref arg & ... [m1] : void |
+| aliasing.cpp:9:11:9:20 | call to user_input : void | aliasing.cpp:9:3:9:22 | s [post update] : void |
+| aliasing.cpp:13:3:13:21 | (reference dereference) [post update] : void | aliasing.cpp:13:3:13:21 | (reference dereference) [post update] [m1] : void |
+| aliasing.cpp:13:3:13:21 | (reference dereference) [post update] [m1] : void | aliasing.cpp:26:19:26:20 | ref arg (reference to) [m1] : void |
+| aliasing.cpp:13:10:13:19 | call to user_input : void | aliasing.cpp:13:3:13:21 | (reference dereference) [post update] : void |
+| aliasing.cpp:25:17:25:19 | ref arg & ... [m1] : void | aliasing.cpp:29:8:29:9 | s1 [m1] : void |
+| aliasing.cpp:26:19:26:20 | ref arg (reference to) [m1] : void | aliasing.cpp:30:8:30:9 | s2 [m1] : void |
+| aliasing.cpp:29:8:29:9 | s1 [m1] : void | aliasing.cpp:29:11:29:12 | m1 |
+| aliasing.cpp:30:8:30:9 | s2 [m1] : void | aliasing.cpp:30:11:30:12 | m1 |
+| aliasing.cpp:37:3:37:24 | (reference dereference) [post update] : void | aliasing.cpp:38:11:38:12 | m1 |
+| aliasing.cpp:37:13:37:22 | call to user_input : void | aliasing.cpp:37:3:37:24 | (reference dereference) [post update] : void |
| aliasing.cpp:37:13:37:22 | call to user_input : void | aliasing.cpp:38:11:38:12 | m1 |
+| aliasing.cpp:42:3:42:22 | s2 [post update] : void | aliasing.cpp:43:13:43:14 | m1 |
+| aliasing.cpp:42:11:42:20 | call to user_input : void | aliasing.cpp:42:3:42:22 | s2 [post update] : void |
| aliasing.cpp:42:11:42:20 | call to user_input : void | aliasing.cpp:43:13:43:14 | m1 |
+| aliasing.cpp:79:3:79:22 | s [post update] : void | aliasing.cpp:80:12:80:13 | m1 |
+| aliasing.cpp:79:11:79:20 | call to user_input : void | aliasing.cpp:79:3:79:22 | s [post update] : void |
| aliasing.cpp:79:11:79:20 | call to user_input : void | aliasing.cpp:80:12:80:13 | m1 |
+| aliasing.cpp:86:3:86:21 | (reference dereference) [post update] : void | aliasing.cpp:87:12:87:13 | m1 |
+| aliasing.cpp:86:10:86:19 | call to user_input : void | aliasing.cpp:86:3:86:21 | (reference dereference) [post update] : void |
| aliasing.cpp:86:10:86:19 | call to user_input : void | aliasing.cpp:87:12:87:13 | m1 |
+| aliasing.cpp:92:3:92:23 | s [post update] : void | aliasing.cpp:93:12:93:13 | m1 |
+| aliasing.cpp:92:12:92:21 | call to user_input : void | aliasing.cpp:92:3:92:23 | s [post update] : void |
| aliasing.cpp:92:12:92:21 | call to user_input : void | aliasing.cpp:93:12:93:13 | m1 |
+| struct_init.c:20:20:20:29 | VariableAddress [post update] : void | struct_init.c:22:11:22:11 | a |
+| struct_init.c:20:20:20:29 | call to user_input : void | struct_init.c:20:20:20:29 | VariableAddress [post update] : void |
| struct_init.c:20:20:20:29 | call to user_input : void | struct_init.c:22:11:22:11 | a |
+| struct_init.c:27:7:27:16 | FieldAddress [post update] : void | struct_init.c:31:23:31:23 | a |
+| struct_init.c:27:7:27:16 | call to user_input : void | struct_init.c:27:7:27:16 | FieldAddress [post update] : void |
| struct_init.c:27:7:27:16 | call to user_input : void | struct_init.c:31:23:31:23 | a |
nodes
+| A.cpp:126:5:126:5 | ref arg b [c] : void | semmle.label | ref arg b [c] : void |
+| A.cpp:126:12:126:18 | new : void | semmle.label | new : void |
+| A.cpp:131:8:131:8 | ref arg b [c] : void | semmle.label | ref arg b [c] : void |
+| A.cpp:132:10:132:10 | b [c] : void | semmle.label | b [c] : void |
+| A.cpp:132:10:132:13 | (void *)... | semmle.label | (void *)... |
+| A.cpp:132:13:132:13 | c | semmle.label | c |
+| A.cpp:132:13:132:13 | c : void | semmle.label | c : void |
+| aliasing.cpp:9:3:9:22 | s [post update] : void | semmle.label | s [post update] : void |
+| aliasing.cpp:9:3:9:22 | s [post update] [m1] : void | semmle.label | s [post update] [m1] : void |
+| aliasing.cpp:9:11:9:20 | call to user_input : void | semmle.label | call to user_input : void |
+| aliasing.cpp:13:3:13:21 | (reference dereference) [post update] : void | semmle.label | (reference dereference) [post update] : void |
+| aliasing.cpp:13:3:13:21 | (reference dereference) [post update] [m1] : void | semmle.label | (reference dereference) [post update] [m1] : void |
+| aliasing.cpp:13:10:13:19 | call to user_input : void | semmle.label | call to user_input : void |
+| aliasing.cpp:25:17:25:19 | ref arg & ... [m1] : void | semmle.label | ref arg & ... [m1] : void |
+| aliasing.cpp:26:19:26:20 | ref arg (reference to) [m1] : void | semmle.label | ref arg (reference to) [m1] : void |
+| aliasing.cpp:29:8:29:9 | s1 [m1] : void | semmle.label | s1 [m1] : void |
+| aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 |
+| aliasing.cpp:30:8:30:9 | s2 [m1] : void | semmle.label | s2 [m1] : void |
+| aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 |
+| aliasing.cpp:37:3:37:24 | (reference dereference) [post update] : void | semmle.label | (reference dereference) [post update] : void |
| aliasing.cpp:37:13:37:22 | call to user_input : void | semmle.label | call to user_input : void |
| aliasing.cpp:38:11:38:12 | m1 | semmle.label | m1 |
+| aliasing.cpp:42:3:42:22 | s2 [post update] : void | semmle.label | s2 [post update] : void |
| aliasing.cpp:42:11:42:20 | call to user_input : void | semmle.label | call to user_input : void |
| aliasing.cpp:43:13:43:14 | m1 | semmle.label | m1 |
+| aliasing.cpp:79:3:79:22 | s [post update] : void | semmle.label | s [post update] : void |
| aliasing.cpp:79:11:79:20 | call to user_input : void | semmle.label | call to user_input : void |
| aliasing.cpp:80:12:80:13 | m1 | semmle.label | m1 |
+| aliasing.cpp:86:3:86:21 | (reference dereference) [post update] : void | semmle.label | (reference dereference) [post update] : void |
| aliasing.cpp:86:10:86:19 | call to user_input : void | semmle.label | call to user_input : void |
| aliasing.cpp:87:12:87:13 | m1 | semmle.label | m1 |
+| aliasing.cpp:92:3:92:23 | s [post update] : void | semmle.label | s [post update] : void |
| aliasing.cpp:92:12:92:21 | call to user_input : void | semmle.label | call to user_input : void |
| aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 |
+| struct_init.c:20:20:20:29 | VariableAddress [post update] : void | semmle.label | VariableAddress [post update] : void |
| struct_init.c:20:20:20:29 | call to user_input : void | semmle.label | call to user_input : void |
| struct_init.c:22:11:22:11 | a | semmle.label | a |
+| struct_init.c:27:7:27:16 | FieldAddress [post update] : void | semmle.label | FieldAddress [post update] : void |
| struct_init.c:27:7:27:16 | call to user_input : void | semmle.label | call to user_input : void |
| struct_init.c:31:23:31:23 | a | semmle.label | a |
#select
+| A.cpp:132:10:132:13 | (void *)... | A.cpp:126:12:126:18 | new : void | A.cpp:132:10:132:13 | (void *)... | (void *)... flows from $@ | A.cpp:126:12:126:18 | new : void | new : void |
+| A.cpp:132:13:132:13 | c | A.cpp:126:12:126:18 | new : void | A.cpp:132:13:132:13 | c | c flows from $@ | A.cpp:126:12:126:18 | new : void | new : void |
+| aliasing.cpp:29:11:29:12 | m1 | aliasing.cpp:9:11:9:20 | call to user_input : void | aliasing.cpp:29:11:29:12 | m1 | m1 flows from $@ | aliasing.cpp:9:11:9:20 | call to user_input : void | call to user_input : void |
+| aliasing.cpp:30:11:30:12 | m1 | aliasing.cpp:13:10:13:19 | call to user_input : void | aliasing.cpp:30:11:30:12 | m1 | m1 flows from $@ | aliasing.cpp:13:10:13:19 | call to user_input : void | call to user_input : void |
| aliasing.cpp:38:11:38:12 | m1 | aliasing.cpp:37:13:37:22 | call to user_input : void | aliasing.cpp:38:11:38:12 | m1 | m1 flows from $@ | aliasing.cpp:37:13:37:22 | call to user_input : void | call to user_input : void |
| aliasing.cpp:43:13:43:14 | m1 | aliasing.cpp:42:11:42:20 | call to user_input : void | aliasing.cpp:43:13:43:14 | m1 | m1 flows from $@ | aliasing.cpp:42:11:42:20 | call to user_input : void | call to user_input : void |
| aliasing.cpp:80:12:80:13 | m1 | aliasing.cpp:79:11:79:20 | call to user_input : void | aliasing.cpp:80:12:80:13 | m1 | m1 flows from $@ | aliasing.cpp:79:11:79:20 | call to user_input : void | call to user_input : void |
From f92dd3c5654d7a17be7418993d59ac0a938344c5 Mon Sep 17 00:00:00 2001
From: Mathias Vorreiter Pedersen
Date: Tue, 24 Mar 2020 22:24:48 +0100
Subject: [PATCH 0008/1298] C++: Autoformat
---
.../src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
index 2b88cc7ade1..93aa394d599 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
@@ -151,9 +151,7 @@ class ParameterNode extends InstructionNode {
* Holds if this node is the parameter of `c` at the specified (zero-based)
* position. The implicit `this` parameter is considered to have index `-1`.
*/
- predicate isParameterOf(Function f, int i) {
- none()
- }
+ predicate isParameterOf(Function f, int i) { none() }
}
/**
From b622d62d3c5250ca6335b28d80a283e8208d4f5c Mon Sep 17 00:00:00 2001
From: Jonas Jensen
Date: Thu, 12 Mar 2020 13:09:56 +0100
Subject: [PATCH 0009/1298] C++: Wire up param/arg indirections in data flow
---
.../ir/dataflow/internal/DataFlowPrivate.qll | 18 +++-
.../cpp/ir/dataflow/internal/DataFlowUtil.qll | 88 ++++++++++++++++---
.../dataflow-tests/test_diff.expected | 1 -
.../dataflow/dataflow-tests/test_ir.expected | 1 +
.../dataflow/taint-tests/test_diff.expected | 2 -
.../dataflow/taint-tests/test_ir.expected | 2 +
6 files changed, 92 insertions(+), 20 deletions(-)
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
index 83e5d5eb06b..1f17af2ca8a 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
@@ -8,16 +8,28 @@ private import DataFlowDispatch
* to the callable. Instance arguments (`this` pointer) are also included.
*/
class ArgumentNode extends InstructionNode {
- ArgumentNode() { exists(CallInstruction call | this.getInstruction() = call.getAnArgument()) }
+ ArgumentNode() {
+ exists(CallInstruction call |
+ instr = call.getAnArgument()
+ or
+ instr.(ReadSideEffectInstruction).getPrimaryInstruction() = call
+ )
+ }
/**
* Holds if this argument occurs at the given position in the given call.
* The instance argument is considered to have index `-1`.
*/
predicate argumentOf(DataFlowCall call, int pos) {
- this.getInstruction() = call.getPositionalArgument(pos)
+ instr = call.getPositionalArgument(pos)
or
- this.getInstruction() = call.getThisArgument() and pos = -1
+ instr = call.getThisArgument() and pos = -1
+ or
+ exists(ReadSideEffectInstruction read |
+ read = instr and
+ read.getPrimaryInstruction() = call and
+ pos = getArgumentPosOfSideEffect(read.getIndex())
+ )
}
/** Gets the call in which this node is an argument. */
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
index e19912a63ee..48eb969abad 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
@@ -54,8 +54,8 @@ class Node extends TIRDataFlowNode {
/** Gets the argument that defines this `DefinitionByReferenceNode`, if any. */
Expr asDefiningArgument() { result = this.(DefinitionByReferenceNode).getArgument() }
- /** Gets the parameter corresponding to this node, if any. */
- Parameter asParameter() { result = this.(ParameterNode).getParameter() }
+ /** Gets the positional parameter corresponding to this node, if any. */
+ Parameter asParameter() { result = this.(PositionalParameterNode).getParameter() }
/**
* Gets the variable corresponding to this node, if any. This can be used for
@@ -142,30 +142,72 @@ class ExprNode extends InstructionNode {
override string toString() { result = this.asConvertedExpr().toString() }
}
+/**
+ * INTERNAL: do not use. Translates a parameter/argument index into a negative
+ * number that denotes the index of its side effect (pointer indirection).
+ */
+bindingset[index]
+int getArgumentPosOfSideEffect(int index) {
+ // -1 -> -2
+ // 0 -> -3
+ // 1 -> -4
+ // ...
+ result = -3 - index
+}
+
/**
* The value of a parameter at function entry, viewed as a node in a data
* flow graph.
*/
-class ParameterNode extends InstructionNode {
- override InitializeParameterInstruction instr;
-
+abstract class ParameterNode extends InstructionNode {
/**
- * Holds if this node is the parameter of `c` at the specified (zero-based)
- * position. The implicit `this` parameter is considered to have index `-1`.
+ * Holds if this node is the parameter of `f` at the specified position. The
+ * implicit `this` parameter is considered to have position `-1`, and
+ * pointer-indirection parameters are at further negative positions.
*/
- predicate isParameterOf(Function f, int i) { f.getParameter(i) = instr.getParameter() }
-
- Parameter getParameter() { result = instr.getParameter() }
-
- override string toString() { result = instr.getParameter().toString() }
+ abstract predicate isParameterOf(Function f, int pos);
}
-private class ThisParameterNode extends InstructionNode {
+private class ThisParameterNode extends ParameterNode {
override InitializeThisInstruction instr;
+ override predicate isParameterOf(Function f, int pos) {
+ pos = -1 and
+ instr.getEnclosingFunction() = f
+ }
+
override string toString() { result = "this" }
}
+class PositionalParameterNode extends ParameterNode {
+ override InitializeParameterInstruction instr;
+
+ override predicate isParameterOf(Function f, int pos) {
+ f.getParameter(pos) = instr.getParameter()
+ }
+
+ /** Gets the `Parameter` associated with this node. */
+ Parameter getParameter() { result = instr.getParameter() }
+
+ override string toString() { result = this.getParameter().toString() }
+}
+
+private class ParameterIndirectionNode extends ParameterNode {
+ override InitializeIndirectionInstruction instr;
+
+ override predicate isParameterOf(Function f, int pos) {
+ exists(int index |
+ f.getParameter(index) = instr.getParameter() and
+ pos = getArgumentPosOfSideEffect(index)
+ )
+ }
+
+ /** Gets the `Parameter` associated with this node. */
+ Parameter getParameter() { result = instr.getParameter() }
+
+ override string toString() { result = "*" + this.getParameter().toString() }
+}
+
/**
* DEPRECATED: Data flow was never an accurate way to determine what
* expressions might be uninitialized. It errs on the side of saying that
@@ -294,7 +336,7 @@ ExprNode convertedExprNode(Expr e) { result.getExpr() = e }
/**
* Gets the `Node` corresponding to the value of `p` at function entry.
*/
-ParameterNode parameterNode(Parameter p) { result.getParameter() = p }
+PositionalParameterNode parameterNode(Parameter p) { result.getParameter() = p }
/** Gets the `VariableNode` corresponding to the variable `v`. */
VariableNode variableNode(Variable v) { result.getVariable() = v }
@@ -328,6 +370,24 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction
or
iTo.(PhiInstruction).getAnOperand().getDef() = iFrom
or
+ // A read side effect is almost never exact since we don't know exactly how
+ // much memory the callee will read.
+ iTo.(ReadSideEffectInstruction).getSideEffectOperand().getAnyDef() = iFrom and
+ not iFrom.isResultConflated()
+ or
+ // Loading a single `int` from an `int *` parameter is not an exact load since
+ // the parameter may point to an entire array rather than a single `int`. The
+ // following rule ensures that any flow going into the
+ // `InitializeIndirectionInstruction`, even if it's for a different array
+ // element, will propagate to a load of the first element.
+ //
+ // Since we're linking `InitializeIndirectionInstruction` and
+ // `LoadInstruction` together directly, this rule will break if there's any
+ // reassignment of the parameter indirection, including a conditional one that
+ // leads to a phi node.
+ iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() =
+ iFrom.(InitializeIndirectionInstruction)
+ or
// Treat all conversions as flow, even conversions between different numeric types.
iTo.(ConvertInstruction).getUnary() = iFrom
or
diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected
index 71630f892f5..97a2eca5b2d 100644
--- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected
+++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected
@@ -23,7 +23,6 @@
| lambdas.cpp:8:10:8:15 | lambdas.cpp:18:8:18:8 | AST only |
| lambdas.cpp:8:10:8:15 | lambdas.cpp:21:3:21:6 | AST only |
| lambdas.cpp:8:10:8:15 | lambdas.cpp:29:3:29:6 | AST only |
-| lambdas.cpp:8:10:8:15 | lambdas.cpp:41:8:41:8 | AST only |
| lambdas.cpp:43:7:43:12 | lambdas.cpp:46:7:46:7 | AST only |
| ref.cpp:29:11:29:16 | ref.cpp:62:10:62:11 | AST only |
| ref.cpp:53:9:53:10 | ref.cpp:56:10:56:11 | AST only |
diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected
index 275cbabc075..7ea30c7e4ee 100644
--- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected
+++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected
@@ -39,6 +39,7 @@
| globals.cpp:12:10:12:24 | flowTestGlobal1 | globals.cpp:13:23:13:28 | call to source |
| globals.cpp:19:10:19:24 | flowTestGlobal2 | globals.cpp:23:23:23:28 | call to source |
| lambdas.cpp:35:8:35:8 | a | lambdas.cpp:8:10:8:15 | call to source |
+| lambdas.cpp:41:8:41:8 | (reference dereference) | lambdas.cpp:8:10:8:15 | call to source |
| test.cpp:7:8:7:9 | t1 | test.cpp:6:12:6:17 | call to source |
| test.cpp:9:8:9:9 | t1 | test.cpp:6:12:6:17 | call to source |
| test.cpp:10:8:10:9 | t2 | test.cpp:6:12:6:17 | call to source |
diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected
index 7680193da16..5c08dbfadec 100644
--- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected
+++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected
@@ -20,7 +20,6 @@
| taint.cpp:130:7:130:9 | taint.cpp:127:8:127:13 | IR only |
| taint.cpp:137:7:137:9 | taint.cpp:120:11:120:16 | AST only |
| taint.cpp:173:8:173:13 | taint.cpp:164:19:164:24 | AST only |
-| taint.cpp:181:8:181:9 | taint.cpp:185:11:185:16 | AST only |
| taint.cpp:195:7:195:7 | taint.cpp:192:23:192:28 | AST only |
| taint.cpp:195:7:195:7 | taint.cpp:193:6:193:6 | AST only |
| taint.cpp:216:7:216:7 | taint.cpp:207:6:207:11 | AST only |
@@ -28,7 +27,6 @@
| taint.cpp:233:8:233:8 | taint.cpp:223:10:223:15 | AST only |
| taint.cpp:236:3:236:6 | taint.cpp:223:10:223:15 | AST only |
| taint.cpp:244:3:244:6 | taint.cpp:223:10:223:15 | AST only |
-| taint.cpp:256:8:256:8 | taint.cpp:223:10:223:15 | AST only |
| taint.cpp:261:7:261:7 | taint.cpp:258:7:258:12 | AST only |
| taint.cpp:351:7:351:7 | taint.cpp:330:6:330:11 | AST only |
| taint.cpp:352:7:352:7 | taint.cpp:330:6:330:11 | AST only |
diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected
index b38de345220..ce27d430a5e 100644
--- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected
+++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected
@@ -8,9 +8,11 @@
| taint.cpp:151:7:151:12 | call to select | taint.cpp:151:20:151:25 | call to source |
| taint.cpp:167:8:167:13 | call to source | taint.cpp:167:8:167:13 | call to source |
| taint.cpp:168:8:168:14 | tainted | taint.cpp:164:19:164:24 | call to source |
+| taint.cpp:181:8:181:9 | * ... | taint.cpp:185:11:185:16 | call to source |
| taint.cpp:210:7:210:7 | x | taint.cpp:207:6:207:11 | call to source |
| taint.cpp:215:7:215:7 | x | taint.cpp:207:6:207:11 | call to source |
| taint.cpp:250:8:250:8 | a | taint.cpp:223:10:223:15 | call to source |
+| taint.cpp:256:8:256:8 | (reference dereference) | taint.cpp:223:10:223:15 | call to source |
| taint.cpp:280:7:280:7 | t | taint.cpp:275:6:275:11 | call to source |
| taint.cpp:289:7:289:7 | t | taint.cpp:275:6:275:11 | call to source |
| taint.cpp:290:7:290:7 | x | taint.cpp:275:6:275:11 | call to source |
From fbef146a497e492d3cc5deb877c6b0f147421c34 Mon Sep 17 00:00:00 2001
From: Mathias Vorreiter Pedersen
Date: Thu, 26 Mar 2020 11:39:20 +0100
Subject: [PATCH 0010/1298] C++: Remove
PositionalArgumentWithoutWriteSideEffectNode (since not all arguments need a
PostUpdateNode). Also generalized the added flow rule in simpleLocalFlowStep
since there isn't always a ChiInstruction - for instance of it's a write to a
struct that only has a single field.
---
.../cpp/ir/dataflow/internal/DataFlowUtil.qll | 36 ++++++++-----------
.../dataflow/fields/ir-flow.expected | 35 ++++++++++++++++++
2 files changed, 50 insertions(+), 21 deletions(-)
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
index 93aa394d599..a811cd795ac 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
@@ -218,7 +218,17 @@ abstract class PostUpdateNode extends InstructionNode {
override string toString() { result = getPreUpdateNode().toString() + " [post update]" }
}
-abstract class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { }
+abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode {
+ final Instruction getInstructionOrChi() {
+ exists(ChiInstruction chi |
+ // TODO: This should be a non-conflated ChiInstruction once #3123 is merged
+ chi.getPartial() = getInstruction() and
+ result = chi
+ )
+ or
+ result = getInstruction()
+ }
+}
class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
override StoreInstruction instr;
@@ -268,22 +278,6 @@ class DefinitionByReferenceNode extends PartialDefinitionNode {
override string toString() { result = "ref arg " + getPreUpdateNode().toString() }
}
-class PositionalArgumentWithoutWriteSideEffectNode extends PartialDefinitionNode {
- override CallInstruction instr;
- PositionalArgumentOperand op;
-
- PositionalArgumentWithoutWriteSideEffectNode() {
- instr.getAnOperand() = op and
- not exists(WriteSideEffectInstruction write |
- write.getIndex() = op.getIndex() and write.getPrimaryInstruction() = instr
- )
- }
-
- override Node getPreUpdateNode() { result.asInstruction() = op.getDef() }
-
- override string toString() { result = "no change to " + op.toString() }
-}
-
/**
* A `Node` corresponding to a variable in the program, as opposed to the
* value of that variable at some particular point. This can be used for
@@ -365,10 +359,10 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction())
or
- exists(ChiInstruction chi, LoadInstruction load |
- chi.getPartial() = nodeFrom.(PartialDefinitionNode).getInstruction() and
- // TODO: This can probably be getSourceValue() after #3112 is merged
- load.getSourceValueOperand().getAnyDef() = chi and
+ exists(LoadInstruction load |
+ // TODO: These can probably be getSourceValue() after #3112 is merged
+ load.getSourceValueOperand().getAnyDef() =
+ nodeFrom.(PartialDefinitionNode).getInstructionOrChi() and
nodeTo.asInstruction() = load.getSourceAddress().(FieldAddressInstruction).getObjectAddress()
)
}
diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
index c66255c7338..3e665a81199 100644
--- a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
+++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
@@ -15,27 +15,48 @@ edges
| aliasing.cpp:26:19:26:20 | ref arg (reference to) [m1] : void | aliasing.cpp:30:8:30:9 | s2 [m1] : void |
| aliasing.cpp:29:8:29:9 | s1 [m1] : void | aliasing.cpp:29:11:29:12 | m1 |
| aliasing.cpp:30:8:30:9 | s2 [m1] : void | aliasing.cpp:30:11:30:12 | m1 |
+| aliasing.cpp:37:3:37:24 | (reference dereference) [post update] : void | aliasing.cpp:37:3:37:24 | (reference dereference) [post update] [m1] : void |
| aliasing.cpp:37:3:37:24 | (reference dereference) [post update] : void | aliasing.cpp:38:11:38:12 | m1 |
+| aliasing.cpp:37:3:37:24 | (reference dereference) [post update] [m1] : void | aliasing.cpp:38:8:38:9 | s1 [m1] : void |
| aliasing.cpp:37:13:37:22 | call to user_input : void | aliasing.cpp:37:3:37:24 | (reference dereference) [post update] : void |
| aliasing.cpp:37:13:37:22 | call to user_input : void | aliasing.cpp:38:11:38:12 | m1 |
+| aliasing.cpp:38:8:38:9 | s1 [m1] : void | aliasing.cpp:38:11:38:12 | m1 |
+| aliasing.cpp:42:3:42:22 | s2 [post update] : void | aliasing.cpp:42:3:42:22 | s2 [post update] [m1] : void |
| aliasing.cpp:42:3:42:22 | s2 [post update] : void | aliasing.cpp:43:13:43:14 | m1 |
+| aliasing.cpp:42:3:42:22 | s2 [post update] [m1] : void | aliasing.cpp:43:8:43:11 | (reference dereference) [m1] : void |
| aliasing.cpp:42:11:42:20 | call to user_input : void | aliasing.cpp:42:3:42:22 | s2 [post update] : void |
| aliasing.cpp:42:11:42:20 | call to user_input : void | aliasing.cpp:43:13:43:14 | m1 |
+| aliasing.cpp:43:8:43:11 | (reference dereference) [m1] : void | aliasing.cpp:43:13:43:14 | m1 |
+| aliasing.cpp:79:3:79:22 | s [post update] : void | aliasing.cpp:79:3:79:22 | s [post update] [m1] : void |
| aliasing.cpp:79:3:79:22 | s [post update] : void | aliasing.cpp:80:12:80:13 | m1 |
+| aliasing.cpp:79:3:79:22 | s [post update] [m1] : void | aliasing.cpp:80:10:80:10 | s [m1] : void |
| aliasing.cpp:79:11:79:20 | call to user_input : void | aliasing.cpp:79:3:79:22 | s [post update] : void |
| aliasing.cpp:79:11:79:20 | call to user_input : void | aliasing.cpp:80:12:80:13 | m1 |
+| aliasing.cpp:80:10:80:10 | s [m1] : void | aliasing.cpp:80:12:80:13 | m1 |
+| aliasing.cpp:86:3:86:21 | (reference dereference) [post update] : void | aliasing.cpp:86:3:86:21 | (reference dereference) [post update] [m1] : void |
| aliasing.cpp:86:3:86:21 | (reference dereference) [post update] : void | aliasing.cpp:87:12:87:13 | m1 |
+| aliasing.cpp:86:3:86:21 | (reference dereference) [post update] [m1] : void | aliasing.cpp:87:10:87:10 | s [m1] : void |
| aliasing.cpp:86:10:86:19 | call to user_input : void | aliasing.cpp:86:3:86:21 | (reference dereference) [post update] : void |
| aliasing.cpp:86:10:86:19 | call to user_input : void | aliasing.cpp:87:12:87:13 | m1 |
+| aliasing.cpp:87:10:87:10 | s [m1] : void | aliasing.cpp:87:12:87:13 | m1 |
+| aliasing.cpp:92:3:92:23 | s [post update] : void | aliasing.cpp:92:3:92:23 | s [post update] [m1] : void |
| aliasing.cpp:92:3:92:23 | s [post update] : void | aliasing.cpp:93:12:93:13 | m1 |
+| aliasing.cpp:92:3:92:23 | s [post update] [m1] : void | aliasing.cpp:93:10:93:10 | s [m1] : void |
| aliasing.cpp:92:12:92:21 | call to user_input : void | aliasing.cpp:92:3:92:23 | s [post update] : void |
| aliasing.cpp:92:12:92:21 | call to user_input : void | aliasing.cpp:93:12:93:13 | m1 |
+| aliasing.cpp:93:10:93:10 | s [m1] : void | aliasing.cpp:93:12:93:13 | m1 |
+| struct_init.c:20:20:20:29 | VariableAddress [post update] : void | struct_init.c:20:20:20:29 | VariableAddress [post update] [a] : void |
| struct_init.c:20:20:20:29 | VariableAddress [post update] : void | struct_init.c:22:11:22:11 | a |
+| struct_init.c:20:20:20:29 | VariableAddress [post update] [a] : void | struct_init.c:22:8:22:9 | ab [a] : void |
| struct_init.c:20:20:20:29 | call to user_input : void | struct_init.c:20:20:20:29 | VariableAddress [post update] : void |
| struct_init.c:20:20:20:29 | call to user_input : void | struct_init.c:22:11:22:11 | a |
+| struct_init.c:22:8:22:9 | ab [a] : void | struct_init.c:22:11:22:11 | a |
+| struct_init.c:27:7:27:16 | FieldAddress [post update] : void | struct_init.c:27:7:27:16 | FieldAddress [post update] [a] : void |
| struct_init.c:27:7:27:16 | FieldAddress [post update] : void | struct_init.c:31:23:31:23 | a |
+| struct_init.c:27:7:27:16 | FieldAddress [post update] [a] : void | struct_init.c:31:14:31:21 | nestedAB [a] : void |
| struct_init.c:27:7:27:16 | call to user_input : void | struct_init.c:27:7:27:16 | FieldAddress [post update] : void |
| struct_init.c:27:7:27:16 | call to user_input : void | struct_init.c:31:23:31:23 | a |
+| struct_init.c:31:14:31:21 | nestedAB [a] : void | struct_init.c:31:23:31:23 | a |
nodes
| A.cpp:126:5:126:5 | ref arg b [c] : void | semmle.label | ref arg b [c] : void |
| A.cpp:126:12:126:18 | new : void | semmle.label | new : void |
@@ -57,25 +78,39 @@ nodes
| aliasing.cpp:30:8:30:9 | s2 [m1] : void | semmle.label | s2 [m1] : void |
| aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 |
| aliasing.cpp:37:3:37:24 | (reference dereference) [post update] : void | semmle.label | (reference dereference) [post update] : void |
+| aliasing.cpp:37:3:37:24 | (reference dereference) [post update] [m1] : void | semmle.label | (reference dereference) [post update] [m1] : void |
| aliasing.cpp:37:13:37:22 | call to user_input : void | semmle.label | call to user_input : void |
+| aliasing.cpp:38:8:38:9 | s1 [m1] : void | semmle.label | s1 [m1] : void |
| aliasing.cpp:38:11:38:12 | m1 | semmle.label | m1 |
| aliasing.cpp:42:3:42:22 | s2 [post update] : void | semmle.label | s2 [post update] : void |
+| aliasing.cpp:42:3:42:22 | s2 [post update] [m1] : void | semmle.label | s2 [post update] [m1] : void |
| aliasing.cpp:42:11:42:20 | call to user_input : void | semmle.label | call to user_input : void |
+| aliasing.cpp:43:8:43:11 | (reference dereference) [m1] : void | semmle.label | (reference dereference) [m1] : void |
| aliasing.cpp:43:13:43:14 | m1 | semmle.label | m1 |
| aliasing.cpp:79:3:79:22 | s [post update] : void | semmle.label | s [post update] : void |
+| aliasing.cpp:79:3:79:22 | s [post update] [m1] : void | semmle.label | s [post update] [m1] : void |
| aliasing.cpp:79:11:79:20 | call to user_input : void | semmle.label | call to user_input : void |
+| aliasing.cpp:80:10:80:10 | s [m1] : void | semmle.label | s [m1] : void |
| aliasing.cpp:80:12:80:13 | m1 | semmle.label | m1 |
| aliasing.cpp:86:3:86:21 | (reference dereference) [post update] : void | semmle.label | (reference dereference) [post update] : void |
+| aliasing.cpp:86:3:86:21 | (reference dereference) [post update] [m1] : void | semmle.label | (reference dereference) [post update] [m1] : void |
| aliasing.cpp:86:10:86:19 | call to user_input : void | semmle.label | call to user_input : void |
+| aliasing.cpp:87:10:87:10 | s [m1] : void | semmle.label | s [m1] : void |
| aliasing.cpp:87:12:87:13 | m1 | semmle.label | m1 |
| aliasing.cpp:92:3:92:23 | s [post update] : void | semmle.label | s [post update] : void |
+| aliasing.cpp:92:3:92:23 | s [post update] [m1] : void | semmle.label | s [post update] [m1] : void |
| aliasing.cpp:92:12:92:21 | call to user_input : void | semmle.label | call to user_input : void |
+| aliasing.cpp:93:10:93:10 | s [m1] : void | semmle.label | s [m1] : void |
| aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 |
| struct_init.c:20:20:20:29 | VariableAddress [post update] : void | semmle.label | VariableAddress [post update] : void |
+| struct_init.c:20:20:20:29 | VariableAddress [post update] [a] : void | semmle.label | VariableAddress [post update] [a] : void |
| struct_init.c:20:20:20:29 | call to user_input : void | semmle.label | call to user_input : void |
+| struct_init.c:22:8:22:9 | ab [a] : void | semmle.label | ab [a] : void |
| struct_init.c:22:11:22:11 | a | semmle.label | a |
| struct_init.c:27:7:27:16 | FieldAddress [post update] : void | semmle.label | FieldAddress [post update] : void |
+| struct_init.c:27:7:27:16 | FieldAddress [post update] [a] : void | semmle.label | FieldAddress [post update] [a] : void |
| struct_init.c:27:7:27:16 | call to user_input : void | semmle.label | call to user_input : void |
+| struct_init.c:31:14:31:21 | nestedAB [a] : void | semmle.label | nestedAB [a] : void |
| struct_init.c:31:23:31:23 | a | semmle.label | a |
#select
| A.cpp:132:10:132:13 | (void *)... | A.cpp:126:12:126:18 | new : void | A.cpp:132:10:132:13 | (void *)... | (void *)... flows from $@ | A.cpp:126:12:126:18 | new : void | new : void |
From c6c613840a09768a9267cd582e0768fd65068e56 Mon Sep 17 00:00:00 2001
From: Mathias Vorreiter Pedersen
Date: Thu, 26 Mar 2020 11:43:40 +0100
Subject: [PATCH 0011/1298] C++: Removed toString from PostUpdateNodes. They
were more confusing than helpful
---
.../cpp/ir/dataflow/internal/DataFlowUtil.qll | 4 -
.../dataflow/fields/ir-flow.expected | 122 +++++++++---------
2 files changed, 61 insertions(+), 65 deletions(-)
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
index a811cd795ac..123841c47cf 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
@@ -214,8 +214,6 @@ abstract class PostUpdateNode extends InstructionNode {
* Gets the node before the state update.
*/
abstract Node getPreUpdateNode();
-
- override string toString() { result = getPreUpdateNode().toString() + " [post update]" }
}
abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode {
@@ -274,8 +272,6 @@ class DefinitionByReferenceNode extends PartialDefinitionNode {
Parameter getParameter() {
exists(CallInstruction ci | result = ci.getStaticCallTarget().getParameter(instr.getIndex()))
}
-
- override string toString() { result = "ref arg " + getPreUpdateNode().toString() }
}
/**
diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
index 3e665a81199..f455b37bf49 100644
--- a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
+++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
@@ -1,114 +1,114 @@
edges
-| A.cpp:126:5:126:5 | ref arg b [c] : void | A.cpp:131:8:131:8 | ref arg b [c] : void |
-| A.cpp:126:12:126:18 | new : void | A.cpp:126:5:126:5 | ref arg b [c] : void |
-| A.cpp:131:8:131:8 | ref arg b [c] : void | A.cpp:132:10:132:10 | b [c] : void |
+| A.cpp:126:5:126:5 | IndirectMayWriteSideEffect [c] : void | A.cpp:131:8:131:8 | BufferMayWriteSideEffect [c] : void |
+| A.cpp:126:12:126:18 | new : void | A.cpp:126:5:126:5 | IndirectMayWriteSideEffect [c] : void |
+| A.cpp:131:8:131:8 | BufferMayWriteSideEffect [c] : void | A.cpp:132:10:132:10 | b [c] : void |
| A.cpp:132:10:132:10 | b [c] : void | A.cpp:132:13:132:13 | c |
| A.cpp:132:10:132:10 | b [c] : void | A.cpp:132:13:132:13 | c : void |
| A.cpp:132:13:132:13 | c : void | A.cpp:132:10:132:13 | (void *)... |
-| aliasing.cpp:9:3:9:22 | s [post update] : void | aliasing.cpp:9:3:9:22 | s [post update] [m1] : void |
-| aliasing.cpp:9:3:9:22 | s [post update] [m1] : void | aliasing.cpp:25:17:25:19 | ref arg & ... [m1] : void |
-| aliasing.cpp:9:11:9:20 | call to user_input : void | aliasing.cpp:9:3:9:22 | s [post update] : void |
-| aliasing.cpp:13:3:13:21 | (reference dereference) [post update] : void | aliasing.cpp:13:3:13:21 | (reference dereference) [post update] [m1] : void |
-| aliasing.cpp:13:3:13:21 | (reference dereference) [post update] [m1] : void | aliasing.cpp:26:19:26:20 | ref arg (reference to) [m1] : void |
-| aliasing.cpp:13:10:13:19 | call to user_input : void | aliasing.cpp:13:3:13:21 | (reference dereference) [post update] : void |
-| aliasing.cpp:25:17:25:19 | ref arg & ... [m1] : void | aliasing.cpp:29:8:29:9 | s1 [m1] : void |
-| aliasing.cpp:26:19:26:20 | ref arg (reference to) [m1] : void | aliasing.cpp:30:8:30:9 | s2 [m1] : void |
+| aliasing.cpp:9:3:9:22 | Store : void | aliasing.cpp:9:3:9:22 | Store [m1] : void |
+| aliasing.cpp:9:3:9:22 | Store [m1] : void | aliasing.cpp:25:17:25:19 | BufferMayWriteSideEffect [m1] : void |
+| aliasing.cpp:9:11:9:20 | call to user_input : void | aliasing.cpp:9:3:9:22 | Store : void |
+| aliasing.cpp:13:3:13:21 | Store : void | aliasing.cpp:13:3:13:21 | Store [m1] : void |
+| aliasing.cpp:13:3:13:21 | Store [m1] : void | aliasing.cpp:26:19:26:20 | BufferMayWriteSideEffect [m1] : void |
+| aliasing.cpp:13:10:13:19 | call to user_input : void | aliasing.cpp:13:3:13:21 | Store : void |
+| aliasing.cpp:25:17:25:19 | BufferMayWriteSideEffect [m1] : void | aliasing.cpp:29:8:29:9 | s1 [m1] : void |
+| aliasing.cpp:26:19:26:20 | BufferMayWriteSideEffect [m1] : void | aliasing.cpp:30:8:30:9 | s2 [m1] : void |
| aliasing.cpp:29:8:29:9 | s1 [m1] : void | aliasing.cpp:29:11:29:12 | m1 |
| aliasing.cpp:30:8:30:9 | s2 [m1] : void | aliasing.cpp:30:11:30:12 | m1 |
-| aliasing.cpp:37:3:37:24 | (reference dereference) [post update] : void | aliasing.cpp:37:3:37:24 | (reference dereference) [post update] [m1] : void |
-| aliasing.cpp:37:3:37:24 | (reference dereference) [post update] : void | aliasing.cpp:38:11:38:12 | m1 |
-| aliasing.cpp:37:3:37:24 | (reference dereference) [post update] [m1] : void | aliasing.cpp:38:8:38:9 | s1 [m1] : void |
-| aliasing.cpp:37:13:37:22 | call to user_input : void | aliasing.cpp:37:3:37:24 | (reference dereference) [post update] : void |
+| aliasing.cpp:37:3:37:24 | Store : void | aliasing.cpp:37:3:37:24 | Store [m1] : void |
+| aliasing.cpp:37:3:37:24 | Store : void | aliasing.cpp:38:11:38:12 | m1 |
+| aliasing.cpp:37:3:37:24 | Store [m1] : void | aliasing.cpp:38:8:38:9 | s1 [m1] : void |
+| aliasing.cpp:37:13:37:22 | call to user_input : void | aliasing.cpp:37:3:37:24 | Store : void |
| aliasing.cpp:37:13:37:22 | call to user_input : void | aliasing.cpp:38:11:38:12 | m1 |
| aliasing.cpp:38:8:38:9 | s1 [m1] : void | aliasing.cpp:38:11:38:12 | m1 |
-| aliasing.cpp:42:3:42:22 | s2 [post update] : void | aliasing.cpp:42:3:42:22 | s2 [post update] [m1] : void |
-| aliasing.cpp:42:3:42:22 | s2 [post update] : void | aliasing.cpp:43:13:43:14 | m1 |
-| aliasing.cpp:42:3:42:22 | s2 [post update] [m1] : void | aliasing.cpp:43:8:43:11 | (reference dereference) [m1] : void |
-| aliasing.cpp:42:11:42:20 | call to user_input : void | aliasing.cpp:42:3:42:22 | s2 [post update] : void |
+| aliasing.cpp:42:3:42:22 | Store : void | aliasing.cpp:42:3:42:22 | Store [m1] : void |
+| aliasing.cpp:42:3:42:22 | Store : void | aliasing.cpp:43:13:43:14 | m1 |
+| aliasing.cpp:42:3:42:22 | Store [m1] : void | aliasing.cpp:43:8:43:11 | (reference dereference) [m1] : void |
+| aliasing.cpp:42:11:42:20 | call to user_input : void | aliasing.cpp:42:3:42:22 | Store : void |
| aliasing.cpp:42:11:42:20 | call to user_input : void | aliasing.cpp:43:13:43:14 | m1 |
| aliasing.cpp:43:8:43:11 | (reference dereference) [m1] : void | aliasing.cpp:43:13:43:14 | m1 |
-| aliasing.cpp:79:3:79:22 | s [post update] : void | aliasing.cpp:79:3:79:22 | s [post update] [m1] : void |
-| aliasing.cpp:79:3:79:22 | s [post update] : void | aliasing.cpp:80:12:80:13 | m1 |
-| aliasing.cpp:79:3:79:22 | s [post update] [m1] : void | aliasing.cpp:80:10:80:10 | s [m1] : void |
-| aliasing.cpp:79:11:79:20 | call to user_input : void | aliasing.cpp:79:3:79:22 | s [post update] : void |
+| aliasing.cpp:79:3:79:22 | Store : void | aliasing.cpp:79:3:79:22 | Store [m1] : void |
+| aliasing.cpp:79:3:79:22 | Store : void | aliasing.cpp:80:12:80:13 | m1 |
+| aliasing.cpp:79:3:79:22 | Store [m1] : void | aliasing.cpp:80:10:80:10 | s [m1] : void |
+| aliasing.cpp:79:11:79:20 | call to user_input : void | aliasing.cpp:79:3:79:22 | Store : void |
| aliasing.cpp:79:11:79:20 | call to user_input : void | aliasing.cpp:80:12:80:13 | m1 |
| aliasing.cpp:80:10:80:10 | s [m1] : void | aliasing.cpp:80:12:80:13 | m1 |
-| aliasing.cpp:86:3:86:21 | (reference dereference) [post update] : void | aliasing.cpp:86:3:86:21 | (reference dereference) [post update] [m1] : void |
-| aliasing.cpp:86:3:86:21 | (reference dereference) [post update] : void | aliasing.cpp:87:12:87:13 | m1 |
-| aliasing.cpp:86:3:86:21 | (reference dereference) [post update] [m1] : void | aliasing.cpp:87:10:87:10 | s [m1] : void |
-| aliasing.cpp:86:10:86:19 | call to user_input : void | aliasing.cpp:86:3:86:21 | (reference dereference) [post update] : void |
+| aliasing.cpp:86:3:86:21 | Store : void | aliasing.cpp:86:3:86:21 | Store [m1] : void |
+| aliasing.cpp:86:3:86:21 | Store : void | aliasing.cpp:87:12:87:13 | m1 |
+| aliasing.cpp:86:3:86:21 | Store [m1] : void | aliasing.cpp:87:10:87:10 | s [m1] : void |
+| aliasing.cpp:86:10:86:19 | call to user_input : void | aliasing.cpp:86:3:86:21 | Store : void |
| aliasing.cpp:86:10:86:19 | call to user_input : void | aliasing.cpp:87:12:87:13 | m1 |
| aliasing.cpp:87:10:87:10 | s [m1] : void | aliasing.cpp:87:12:87:13 | m1 |
-| aliasing.cpp:92:3:92:23 | s [post update] : void | aliasing.cpp:92:3:92:23 | s [post update] [m1] : void |
-| aliasing.cpp:92:3:92:23 | s [post update] : void | aliasing.cpp:93:12:93:13 | m1 |
-| aliasing.cpp:92:3:92:23 | s [post update] [m1] : void | aliasing.cpp:93:10:93:10 | s [m1] : void |
-| aliasing.cpp:92:12:92:21 | call to user_input : void | aliasing.cpp:92:3:92:23 | s [post update] : void |
+| aliasing.cpp:92:3:92:23 | Store : void | aliasing.cpp:92:3:92:23 | Store [m1] : void |
+| aliasing.cpp:92:3:92:23 | Store : void | aliasing.cpp:93:12:93:13 | m1 |
+| aliasing.cpp:92:3:92:23 | Store [m1] : void | aliasing.cpp:93:10:93:10 | s [m1] : void |
+| aliasing.cpp:92:12:92:21 | call to user_input : void | aliasing.cpp:92:3:92:23 | Store : void |
| aliasing.cpp:92:12:92:21 | call to user_input : void | aliasing.cpp:93:12:93:13 | m1 |
| aliasing.cpp:93:10:93:10 | s [m1] : void | aliasing.cpp:93:12:93:13 | m1 |
-| struct_init.c:20:20:20:29 | VariableAddress [post update] : void | struct_init.c:20:20:20:29 | VariableAddress [post update] [a] : void |
-| struct_init.c:20:20:20:29 | VariableAddress [post update] : void | struct_init.c:22:11:22:11 | a |
-| struct_init.c:20:20:20:29 | VariableAddress [post update] [a] : void | struct_init.c:22:8:22:9 | ab [a] : void |
-| struct_init.c:20:20:20:29 | call to user_input : void | struct_init.c:20:20:20:29 | VariableAddress [post update] : void |
+| struct_init.c:20:20:20:29 | Store : void | struct_init.c:20:20:20:29 | Store [a] : void |
+| struct_init.c:20:20:20:29 | Store : void | struct_init.c:22:11:22:11 | a |
+| struct_init.c:20:20:20:29 | Store [a] : void | struct_init.c:22:8:22:9 | ab [a] : void |
+| struct_init.c:20:20:20:29 | call to user_input : void | struct_init.c:20:20:20:29 | Store : void |
| struct_init.c:20:20:20:29 | call to user_input : void | struct_init.c:22:11:22:11 | a |
| struct_init.c:22:8:22:9 | ab [a] : void | struct_init.c:22:11:22:11 | a |
-| struct_init.c:27:7:27:16 | FieldAddress [post update] : void | struct_init.c:27:7:27:16 | FieldAddress [post update] [a] : void |
-| struct_init.c:27:7:27:16 | FieldAddress [post update] : void | struct_init.c:31:23:31:23 | a |
-| struct_init.c:27:7:27:16 | FieldAddress [post update] [a] : void | struct_init.c:31:14:31:21 | nestedAB [a] : void |
-| struct_init.c:27:7:27:16 | call to user_input : void | struct_init.c:27:7:27:16 | FieldAddress [post update] : void |
+| struct_init.c:27:7:27:16 | Store : void | struct_init.c:27:7:27:16 | Store [a] : void |
+| struct_init.c:27:7:27:16 | Store : void | struct_init.c:31:23:31:23 | a |
+| struct_init.c:27:7:27:16 | Store [a] : void | struct_init.c:31:14:31:21 | nestedAB [a] : void |
+| struct_init.c:27:7:27:16 | call to user_input : void | struct_init.c:27:7:27:16 | Store : void |
| struct_init.c:27:7:27:16 | call to user_input : void | struct_init.c:31:23:31:23 | a |
| struct_init.c:31:14:31:21 | nestedAB [a] : void | struct_init.c:31:23:31:23 | a |
nodes
-| A.cpp:126:5:126:5 | ref arg b [c] : void | semmle.label | ref arg b [c] : void |
+| A.cpp:126:5:126:5 | IndirectMayWriteSideEffect [c] : void | semmle.label | IndirectMayWriteSideEffect [c] : void |
| A.cpp:126:12:126:18 | new : void | semmle.label | new : void |
-| A.cpp:131:8:131:8 | ref arg b [c] : void | semmle.label | ref arg b [c] : void |
+| A.cpp:131:8:131:8 | BufferMayWriteSideEffect [c] : void | semmle.label | BufferMayWriteSideEffect [c] : void |
| A.cpp:132:10:132:10 | b [c] : void | semmle.label | b [c] : void |
| A.cpp:132:10:132:13 | (void *)... | semmle.label | (void *)... |
| A.cpp:132:13:132:13 | c | semmle.label | c |
| A.cpp:132:13:132:13 | c : void | semmle.label | c : void |
-| aliasing.cpp:9:3:9:22 | s [post update] : void | semmle.label | s [post update] : void |
-| aliasing.cpp:9:3:9:22 | s [post update] [m1] : void | semmle.label | s [post update] [m1] : void |
+| aliasing.cpp:9:3:9:22 | Store : void | semmle.label | Store : void |
+| aliasing.cpp:9:3:9:22 | Store [m1] : void | semmle.label | Store [m1] : void |
| aliasing.cpp:9:11:9:20 | call to user_input : void | semmle.label | call to user_input : void |
-| aliasing.cpp:13:3:13:21 | (reference dereference) [post update] : void | semmle.label | (reference dereference) [post update] : void |
-| aliasing.cpp:13:3:13:21 | (reference dereference) [post update] [m1] : void | semmle.label | (reference dereference) [post update] [m1] : void |
+| aliasing.cpp:13:3:13:21 | Store : void | semmle.label | Store : void |
+| aliasing.cpp:13:3:13:21 | Store [m1] : void | semmle.label | Store [m1] : void |
| aliasing.cpp:13:10:13:19 | call to user_input : void | semmle.label | call to user_input : void |
-| aliasing.cpp:25:17:25:19 | ref arg & ... [m1] : void | semmle.label | ref arg & ... [m1] : void |
-| aliasing.cpp:26:19:26:20 | ref arg (reference to) [m1] : void | semmle.label | ref arg (reference to) [m1] : void |
+| aliasing.cpp:25:17:25:19 | BufferMayWriteSideEffect [m1] : void | semmle.label | BufferMayWriteSideEffect [m1] : void |
+| aliasing.cpp:26:19:26:20 | BufferMayWriteSideEffect [m1] : void | semmle.label | BufferMayWriteSideEffect [m1] : void |
| aliasing.cpp:29:8:29:9 | s1 [m1] : void | semmle.label | s1 [m1] : void |
| aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 |
| aliasing.cpp:30:8:30:9 | s2 [m1] : void | semmle.label | s2 [m1] : void |
| aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 |
-| aliasing.cpp:37:3:37:24 | (reference dereference) [post update] : void | semmle.label | (reference dereference) [post update] : void |
-| aliasing.cpp:37:3:37:24 | (reference dereference) [post update] [m1] : void | semmle.label | (reference dereference) [post update] [m1] : void |
+| aliasing.cpp:37:3:37:24 | Store : void | semmle.label | Store : void |
+| aliasing.cpp:37:3:37:24 | Store [m1] : void | semmle.label | Store [m1] : void |
| aliasing.cpp:37:13:37:22 | call to user_input : void | semmle.label | call to user_input : void |
| aliasing.cpp:38:8:38:9 | s1 [m1] : void | semmle.label | s1 [m1] : void |
| aliasing.cpp:38:11:38:12 | m1 | semmle.label | m1 |
-| aliasing.cpp:42:3:42:22 | s2 [post update] : void | semmle.label | s2 [post update] : void |
-| aliasing.cpp:42:3:42:22 | s2 [post update] [m1] : void | semmle.label | s2 [post update] [m1] : void |
+| aliasing.cpp:42:3:42:22 | Store : void | semmle.label | Store : void |
+| aliasing.cpp:42:3:42:22 | Store [m1] : void | semmle.label | Store [m1] : void |
| aliasing.cpp:42:11:42:20 | call to user_input : void | semmle.label | call to user_input : void |
| aliasing.cpp:43:8:43:11 | (reference dereference) [m1] : void | semmle.label | (reference dereference) [m1] : void |
| aliasing.cpp:43:13:43:14 | m1 | semmle.label | m1 |
-| aliasing.cpp:79:3:79:22 | s [post update] : void | semmle.label | s [post update] : void |
-| aliasing.cpp:79:3:79:22 | s [post update] [m1] : void | semmle.label | s [post update] [m1] : void |
+| aliasing.cpp:79:3:79:22 | Store : void | semmle.label | Store : void |
+| aliasing.cpp:79:3:79:22 | Store [m1] : void | semmle.label | Store [m1] : void |
| aliasing.cpp:79:11:79:20 | call to user_input : void | semmle.label | call to user_input : void |
| aliasing.cpp:80:10:80:10 | s [m1] : void | semmle.label | s [m1] : void |
| aliasing.cpp:80:12:80:13 | m1 | semmle.label | m1 |
-| aliasing.cpp:86:3:86:21 | (reference dereference) [post update] : void | semmle.label | (reference dereference) [post update] : void |
-| aliasing.cpp:86:3:86:21 | (reference dereference) [post update] [m1] : void | semmle.label | (reference dereference) [post update] [m1] : void |
+| aliasing.cpp:86:3:86:21 | Store : void | semmle.label | Store : void |
+| aliasing.cpp:86:3:86:21 | Store [m1] : void | semmle.label | Store [m1] : void |
| aliasing.cpp:86:10:86:19 | call to user_input : void | semmle.label | call to user_input : void |
| aliasing.cpp:87:10:87:10 | s [m1] : void | semmle.label | s [m1] : void |
| aliasing.cpp:87:12:87:13 | m1 | semmle.label | m1 |
-| aliasing.cpp:92:3:92:23 | s [post update] : void | semmle.label | s [post update] : void |
-| aliasing.cpp:92:3:92:23 | s [post update] [m1] : void | semmle.label | s [post update] [m1] : void |
+| aliasing.cpp:92:3:92:23 | Store : void | semmle.label | Store : void |
+| aliasing.cpp:92:3:92:23 | Store [m1] : void | semmle.label | Store [m1] : void |
| aliasing.cpp:92:12:92:21 | call to user_input : void | semmle.label | call to user_input : void |
| aliasing.cpp:93:10:93:10 | s [m1] : void | semmle.label | s [m1] : void |
| aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 |
-| struct_init.c:20:20:20:29 | VariableAddress [post update] : void | semmle.label | VariableAddress [post update] : void |
-| struct_init.c:20:20:20:29 | VariableAddress [post update] [a] : void | semmle.label | VariableAddress [post update] [a] : void |
+| struct_init.c:20:20:20:29 | Store : void | semmle.label | Store : void |
+| struct_init.c:20:20:20:29 | Store [a] : void | semmle.label | Store [a] : void |
| struct_init.c:20:20:20:29 | call to user_input : void | semmle.label | call to user_input : void |
| struct_init.c:22:8:22:9 | ab [a] : void | semmle.label | ab [a] : void |
| struct_init.c:22:11:22:11 | a | semmle.label | a |
-| struct_init.c:27:7:27:16 | FieldAddress [post update] : void | semmle.label | FieldAddress [post update] : void |
-| struct_init.c:27:7:27:16 | FieldAddress [post update] [a] : void | semmle.label | FieldAddress [post update] [a] : void |
+| struct_init.c:27:7:27:16 | Store : void | semmle.label | Store : void |
+| struct_init.c:27:7:27:16 | Store [a] : void | semmle.label | Store [a] : void |
| struct_init.c:27:7:27:16 | call to user_input : void | semmle.label | call to user_input : void |
| struct_init.c:31:14:31:21 | nestedAB [a] : void | semmle.label | nestedAB [a] : void |
| struct_init.c:31:23:31:23 | a | semmle.label | a |
From 08c53d4a619c23b2988557b99aa36d6af76db409 Mon Sep 17 00:00:00 2001
From: Jonas Jensen
Date: Thu, 26 Mar 2020 11:57:53 +0100
Subject: [PATCH 0012/1298] C++: Clean up the ParameterNode class tree
The new names are chosen to align with Java's `DataFlowUtil.qll`.
---
.../cpp/ir/dataflow/internal/DataFlowUtil.qll | 32 ++++++++++++++-----
1 file changed, 24 insertions(+), 8 deletions(-)
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
index 48eb969abad..ae3a521f964 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
@@ -55,7 +55,7 @@ class Node extends TIRDataFlowNode {
Expr asDefiningArgument() { result = this.(DefinitionByReferenceNode).getArgument() }
/** Gets the positional parameter corresponding to this node, if any. */
- Parameter asParameter() { result = this.(PositionalParameterNode).getParameter() }
+ Parameter asParameter() { result = this.(ExplicitParameterNode).getParameter() }
/**
* Gets the variable corresponding to this node, if any. This can be used for
@@ -157,18 +157,32 @@ int getArgumentPosOfSideEffect(int index) {
/**
* The value of a parameter at function entry, viewed as a node in a data
- * flow graph.
+ * flow graph. This type includes implicit parameters.
+ *
+ * To match a specific kind of parameter, consider using one of the subclasses
+ * `ExplicitParameterNode`, `InstanceParameterNode`, or
+ * `ParameterIndirectionNode`.
*/
-abstract class ParameterNode extends InstructionNode {
+class ParameterNode extends InstructionNode {
+ ParameterNode() {
+ // To avoid making this class abstract, we enumerate its values here
+ instr instanceof InitializeThisInstruction
+ or
+ instr instanceof InitializeParameterInstruction
+ or
+ instr instanceof InitializeIndirectionInstruction
+ }
+
/**
* Holds if this node is the parameter of `f` at the specified position. The
* implicit `this` parameter is considered to have position `-1`, and
* pointer-indirection parameters are at further negative positions.
*/
- abstract predicate isParameterOf(Function f, int pos);
+ predicate isParameterOf(Function f, int pos) { none() } // overridden in subclasses
}
-private class ThisParameterNode extends ParameterNode {
+/** An implicit `this` parameter. */
+class InstanceParameterNode extends ParameterNode {
override InitializeThisInstruction instr;
override predicate isParameterOf(Function f, int pos) {
@@ -179,7 +193,8 @@ private class ThisParameterNode extends ParameterNode {
override string toString() { result = "this" }
}
-class PositionalParameterNode extends ParameterNode {
+/** An explicit positional parameter, not including `this` or `...`. */
+class ExplicitParameterNode extends ParameterNode {
override InitializeParameterInstruction instr;
override predicate isParameterOf(Function f, int pos) {
@@ -192,7 +207,8 @@ class PositionalParameterNode extends ParameterNode {
override string toString() { result = this.getParameter().toString() }
}
-private class ParameterIndirectionNode extends ParameterNode {
+/** A virtual parameter to model the pointed-to object of a pointer parameter. */
+class ParameterIndirectionNode extends ParameterNode {
override InitializeIndirectionInstruction instr;
override predicate isParameterOf(Function f, int pos) {
@@ -336,7 +352,7 @@ ExprNode convertedExprNode(Expr e) { result.getExpr() = e }
/**
* Gets the `Node` corresponding to the value of `p` at function entry.
*/
-PositionalParameterNode parameterNode(Parameter p) { result.getParameter() = p }
+ExplicitParameterNode parameterNode(Parameter p) { result.getParameter() = p }
/** Gets the `VariableNode` corresponding to the variable `v`. */
VariableNode variableNode(Variable v) { result.getVariable() = v }
From 5ba5791ec6511b31591b11313da570bcb86a57c6 Mon Sep 17 00:00:00 2001
From: Mathias Vorreiter Pedersen
Date: Fri, 27 Mar 2020 13:37:17 +0100
Subject: [PATCH 0013/1298] C++: Only allow flow through non-conflated chi
instructions
---
.../cpp/ir/dataflow/internal/DataFlowUtil.qll | 3 +--
.../dataflow/fields/ir-flow.expected | 15 ---------------
2 files changed, 1 insertion(+), 17 deletions(-)
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
index 123841c47cf..367d49bb2a7 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
@@ -219,7 +219,7 @@ abstract class PostUpdateNode extends InstructionNode {
abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode {
final Instruction getInstructionOrChi() {
exists(ChiInstruction chi |
- // TODO: This should be a non-conflated ChiInstruction once #3123 is merged
+ not chi.isResultConflated() and
chi.getPartial() = getInstruction() and
result = chi
)
@@ -356,7 +356,6 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction())
or
exists(LoadInstruction load |
- // TODO: These can probably be getSourceValue() after #3112 is merged
load.getSourceValueOperand().getAnyDef() =
nodeFrom.(PartialDefinitionNode).getInstructionOrChi() and
nodeTo.asInstruction() = load.getSourceAddress().(FieldAddressInstruction).getObjectAddress()
diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
index f455b37bf49..3c7bbe96a7d 100644
--- a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
+++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
@@ -1,10 +1,4 @@
edges
-| A.cpp:126:5:126:5 | IndirectMayWriteSideEffect [c] : void | A.cpp:131:8:131:8 | BufferMayWriteSideEffect [c] : void |
-| A.cpp:126:12:126:18 | new : void | A.cpp:126:5:126:5 | IndirectMayWriteSideEffect [c] : void |
-| A.cpp:131:8:131:8 | BufferMayWriteSideEffect [c] : void | A.cpp:132:10:132:10 | b [c] : void |
-| A.cpp:132:10:132:10 | b [c] : void | A.cpp:132:13:132:13 | c |
-| A.cpp:132:10:132:10 | b [c] : void | A.cpp:132:13:132:13 | c : void |
-| A.cpp:132:13:132:13 | c : void | A.cpp:132:10:132:13 | (void *)... |
| aliasing.cpp:9:3:9:22 | Store : void | aliasing.cpp:9:3:9:22 | Store [m1] : void |
| aliasing.cpp:9:3:9:22 | Store [m1] : void | aliasing.cpp:25:17:25:19 | BufferMayWriteSideEffect [m1] : void |
| aliasing.cpp:9:11:9:20 | call to user_input : void | aliasing.cpp:9:3:9:22 | Store : void |
@@ -58,13 +52,6 @@ edges
| struct_init.c:27:7:27:16 | call to user_input : void | struct_init.c:31:23:31:23 | a |
| struct_init.c:31:14:31:21 | nestedAB [a] : void | struct_init.c:31:23:31:23 | a |
nodes
-| A.cpp:126:5:126:5 | IndirectMayWriteSideEffect [c] : void | semmle.label | IndirectMayWriteSideEffect [c] : void |
-| A.cpp:126:12:126:18 | new : void | semmle.label | new : void |
-| A.cpp:131:8:131:8 | BufferMayWriteSideEffect [c] : void | semmle.label | BufferMayWriteSideEffect [c] : void |
-| A.cpp:132:10:132:10 | b [c] : void | semmle.label | b [c] : void |
-| A.cpp:132:10:132:13 | (void *)... | semmle.label | (void *)... |
-| A.cpp:132:13:132:13 | c | semmle.label | c |
-| A.cpp:132:13:132:13 | c : void | semmle.label | c : void |
| aliasing.cpp:9:3:9:22 | Store : void | semmle.label | Store : void |
| aliasing.cpp:9:3:9:22 | Store [m1] : void | semmle.label | Store [m1] : void |
| aliasing.cpp:9:11:9:20 | call to user_input : void | semmle.label | call to user_input : void |
@@ -113,8 +100,6 @@ nodes
| struct_init.c:31:14:31:21 | nestedAB [a] : void | semmle.label | nestedAB [a] : void |
| struct_init.c:31:23:31:23 | a | semmle.label | a |
#select
-| A.cpp:132:10:132:13 | (void *)... | A.cpp:126:12:126:18 | new : void | A.cpp:132:10:132:13 | (void *)... | (void *)... flows from $@ | A.cpp:126:12:126:18 | new : void | new : void |
-| A.cpp:132:13:132:13 | c | A.cpp:126:12:126:18 | new : void | A.cpp:132:13:132:13 | c | c flows from $@ | A.cpp:126:12:126:18 | new : void | new : void |
| aliasing.cpp:29:11:29:12 | m1 | aliasing.cpp:9:11:9:20 | call to user_input : void | aliasing.cpp:29:11:29:12 | m1 | m1 flows from $@ | aliasing.cpp:9:11:9:20 | call to user_input : void | call to user_input : void |
| aliasing.cpp:30:11:30:12 | m1 | aliasing.cpp:13:10:13:19 | call to user_input : void | aliasing.cpp:30:11:30:12 | m1 | m1 flows from $@ | aliasing.cpp:13:10:13:19 | call to user_input : void | call to user_input : void |
| aliasing.cpp:38:11:38:12 | m1 | aliasing.cpp:37:13:37:22 | call to user_input : void | aliasing.cpp:38:11:38:12 | m1 | m1 flows from $@ | aliasing.cpp:37:13:37:22 | call to user_input : void | call to user_input : void |
From 710eb0cab92525ab25734d2e4b83dcb9d5016e88 Mon Sep 17 00:00:00 2001
From: Jonas Jensen
Date: Fri, 27 Mar 2020 17:15:09 +0100
Subject: [PATCH 0014/1298] C++: Replace "min = max" with "unique"
With the new `unique` aggregate added to QL, we can express directly
what the "min = max" pattern emulates.
Replacing "min and max" with `unique` might in general lead to fewer
results, but that happens only in cases where the aggregate expression
has multiple values. For the three predicates changed in this commit,
that should only happen on malformed databases.
---
cpp/ql/src/semmle/code/cpp/commons/Buffer.qll | 8 +-------
.../code/cpp/controlflow/internal/ConstantExprs.qll | 8 +-------
.../aliased_ssa/constant/ConstantAnalysis.qll | 3 +--
.../ir/implementation/raw/constant/ConstantAnalysis.qll | 3 +--
.../unaliased_ssa/constant/ConstantAnalysis.qll | 3 +--
5 files changed, 5 insertions(+), 20 deletions(-)
diff --git a/cpp/ql/src/semmle/code/cpp/commons/Buffer.qll b/cpp/ql/src/semmle/code/cpp/commons/Buffer.qll
index c884038a1c8..88e6a48ff55 100644
--- a/cpp/ql/src/semmle/code/cpp/commons/Buffer.qll
+++ b/cpp/ql/src/semmle/code/cpp/commons/Buffer.qll
@@ -92,13 +92,7 @@ int getBufferSize(Expr bufferExpr, Element why) {
// dataflow (all sources must be the same size)
bufferExprNode = DataFlow::exprNode(bufferExpr) and
result =
- min(Expr def |
- DataFlow::localFlowStep(DataFlow::exprNode(def), bufferExprNode)
- |
- getBufferSize(def, _)
- ) and
- result =
- max(Expr def |
+ unique(Expr def |
DataFlow::localFlowStep(DataFlow::exprNode(def), bufferExprNode)
|
getBufferSize(def, _)
diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/internal/ConstantExprs.qll b/cpp/ql/src/semmle/code/cpp/controlflow/internal/ConstantExprs.qll
index f0af3d219b5..c473f156088 100644
--- a/cpp/ql/src/semmle/code/cpp/controlflow/internal/ConstantExprs.qll
+++ b/cpp/ql/src/semmle/code/cpp/controlflow/internal/ConstantExprs.qll
@@ -532,13 +532,7 @@ library class ExprEvaluator extends int {
interestingVariableAccess(e, va, v, true) and
// All assignments must have the same int value
result =
- min(Expr value |
- value = v.getAnAssignedValue() and not ignoreVariableAssignment(e, v, value)
- |
- getValueInternalNonSubExpr(value)
- ) and
- result =
- max(Expr value |
+ unique(Expr value |
value = v.getAnAssignedValue() and not ignoreVariableAssignment(e, v, value)
|
getValueInternalNonSubExpr(value)
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/constant/ConstantAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/constant/ConstantAnalysis.qll
index 40076b817a1..76f52f8334a 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/constant/ConstantAnalysis.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/constant/ConstantAnalysis.qll
@@ -14,8 +14,7 @@ int getConstantValue(Instruction instr) {
or
exists(PhiInstruction phi |
phi = instr and
- result = max(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef())) and
- result = min(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef()))
+ result = unique(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef()))
)
}
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/constant/ConstantAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/constant/ConstantAnalysis.qll
index 40076b817a1..76f52f8334a 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/constant/ConstantAnalysis.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/constant/ConstantAnalysis.qll
@@ -14,8 +14,7 @@ int getConstantValue(Instruction instr) {
or
exists(PhiInstruction phi |
phi = instr and
- result = max(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef())) and
- result = min(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef()))
+ result = unique(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef()))
)
}
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll
index 40076b817a1..76f52f8334a 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll
@@ -14,8 +14,7 @@ int getConstantValue(Instruction instr) {
or
exists(PhiInstruction phi |
phi = instr and
- result = max(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef())) and
- result = min(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef()))
+ result = unique(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef()))
)
}
From c3a6ca0d9a069b9efadc9a909e14feccb8377f9b Mon Sep 17 00:00:00 2001
From: Dave Bartolomeo
Date: Fri, 27 Mar 2020 18:08:14 -0400
Subject: [PATCH 0015/1298] C++: Better support for complex numbers in IR and
AST
This PR adds better support for differentiating complex and imaginary floating-point types from real floating-point types, in both the AST and in the IR type system.
*AST Changes*
- Introduces the new class `TypeDomain`, which can be either `RealDomain`, `ImaginaryDomain` or `ComplexDomain`. "type domain" is the term used for this concept in the C standard, and I couldn't think of a better one.
- Introduces `FloatingPointType.getDomain()`, to get the type domain of the type.
- Introduces `FloatingPointType.getBase()`, to get the numeric base of the type (either 2 or 10).
- Introduces three new subtypes of `FloatingPointType`: `RealNumberType`, `ComplexNumberType`, and `ImaginaryNumberType`, which differentiate between the types based on their type domain. Note that the decimal types (e.g., `_Decimal32`) are included in `RealNumberType`.
- Introduces two new subtypes of `FloatingPointType`: `BinaryFloatingPointType` and `DecimalFloatingPointType`, which differentiate between the types based on their numeric base, independent of type domain.
*IR Changes*
- `IRFloatingPointType` now has two additional parameters: the base and the type domain.
- New test that ensures that C++ types get mapped to the correct IR types.
- New IR test that verifies the IR for some basic usage of complex FP types.
---
cpp/ql/src/semmle/code/cpp/Type.qll | 201 ++++++++++++++++--
.../code/cpp/ir/implementation/IRType.qll | 43 +++-
.../semmle/code/cpp/ir/internal/CppType.qll | 44 +++-
.../code/cpp/ir/internal/IRCppLanguage.qll | 5 +
.../library-tests/ir/ir/PrintAST.expected | 56 +++++
cpp/ql/test/library-tests/ir/ir/complex.c | 5 +
.../test/library-tests/ir/ir/raw_ir.expected | 33 +++
cpp/ql/test/library-tests/ir/types/complex.c | 6 +
.../test/library-tests/ir/types/irtypes.cpp | 65 ++++++
.../library-tests/ir/types/irtypes.expected | 0
cpp/ql/test/library-tests/ir/types/irtypes.ql | 18 ++
.../code/csharp/ir/implementation/IRType.qll | 43 +++-
.../code/csharp/ir/internal/CSharpType.qll | 14 +-
.../csharp/ir/internal/IRCSharpLanguage.qll | 37 ++++
14 files changed, 526 insertions(+), 44 deletions(-)
create mode 100644 cpp/ql/test/library-tests/ir/ir/complex.c
create mode 100644 cpp/ql/test/library-tests/ir/types/complex.c
create mode 100644 cpp/ql/test/library-tests/ir/types/irtypes.cpp
create mode 100644 cpp/ql/test/library-tests/ir/types/irtypes.expected
create mode 100644 cpp/ql/test/library-tests/ir/types/irtypes.ql
diff --git a/cpp/ql/src/semmle/code/cpp/Type.qll b/cpp/ql/src/semmle/code/cpp/Type.qll
index 38e5efba6df..f6787d00e1a 100644
--- a/cpp/ql/src/semmle/code/cpp/Type.qll
+++ b/cpp/ql/src/semmle/code/cpp/Type.qll
@@ -697,28 +697,187 @@ class Int128Type extends IntegralType {
override string getCanonicalQLClass() { result = "Int128Type" }
}
+private newtype TTypeDomain =
+ TRealDomain() or
+ TComplexDomain() or
+ TImaginaryDomain()
+
/**
- * The C/C++ floating point types. See 4.5. This includes `float`,
- * `double` and `long double` types.
- * ```
- * float f;
- * double d;
- * long double ld;
- * ```
+ * The type domain of a floating-point type. One of `RealDomain`, `ComplexDomain`, or
+ * `ImaginaryDomain`.
+ */
+class TypeDomain extends TTypeDomain {
+ string toString() { none() }
+}
+
+/**
+ * The type domain of a floating-point type that represents a real number.
+ */
+class RealDomain extends TypeDomain, TRealDomain {
+ final override string toString() { result = "real" }
+}
+
+/**
+ * The type domain of a floating-point type that represents a complex number.
+ */
+class ComplexDomain extends TypeDomain, TComplexDomain {
+ final override string toString() { result = "complex" }
+}
+
+/**
+ * The type domain of a floating-point type that represents an imaginary number.
+ */
+class ImaginaryDomain extends TypeDomain, TImaginaryDomain {
+ final override string toString() { result = "imaginary" }
+}
+
+/**
+ * Data for floating-point types.
+ *
+ * kind: The original type kind. Can be any floating-point type kind.
+ * base: The numeric base of the number's representation. Can be 2 (binary) or 10 (decimal).
+ * domain: The type domain of the type. Can be `RealDomain`, `ComplexDomain`, or `ImaginaryDomain`.
+ * realKind: The type kind of the corresponding real type. For example, the corresponding real type
+ * of `_Complex double` is `double`.
+ * extended: `true` if the number is an extended-precision floating-point number, such as
+ * `_Float32x`.
+ */
+private predicate floatingPointTypeMapping(
+ int kind, int base, TTypeDomain domain, int realKind, boolean extended
+) {
+ // float
+ kind = 24 and base = 2 and domain = TRealDomain() and realKind = 24 and extended = false
+ or
+ // double
+ kind = 25 and base = 2 and domain = TRealDomain() and realKind = 25 and extended = false
+ or
+ // long double
+ kind = 26 and base = 2 and domain = TRealDomain() and realKind = 26 and extended = false
+ or
+ // _Complex float
+ kind = 27 and base = 2 and domain = TComplexDomain() and realKind = 24 and extended = false
+ or
+ // _Complex double
+ kind = 28 and base = 2 and domain = TComplexDomain() and realKind = 25 and extended = false
+ or
+ // _Complex long double
+ kind = 29 and base = 2 and domain = TComplexDomain() and realKind = 26 and extended = false
+ or
+ // _Imaginary float
+ kind = 30 and base = 2 and domain = TImaginaryDomain() and realKind = 24 and extended = false
+ or
+ // _Imaginary double
+ kind = 31 and base = 2 and domain = TImaginaryDomain() and realKind = 25 and extended = false
+ or
+ // _Imaginary long double
+ kind = 32 and base = 2 and domain = TImaginaryDomain() and realKind = 26 and extended = false
+ or
+ // __float128
+ kind = 38 and base = 2 and domain = TRealDomain() and realKind = 38 and extended = false
+ or
+ // _Complex __float128
+ kind = 39 and base = 2 and domain = TComplexDomain() and realKind = 38 and extended = false
+ or
+ // _Decimal32
+ kind = 40 and base = 10 and domain = TRealDomain() and realKind = 40 and extended = false
+ or
+ // _Decimal64
+ kind = 41 and base = 10 and domain = TRealDomain() and realKind = 41 and extended = false
+ or
+ // _Decimal128
+ kind = 42 and base = 10 and domain = TRealDomain() and realKind = 42 and extended = false
+ or
+ // _Float32
+ kind = 45 and base = 2 and domain = TRealDomain() and realKind = 45 and extended = false
+ or
+ // _Float32x
+ kind = 46 and base = 2 and domain = TRealDomain() and realKind = 46 and extended = true
+ or
+ // _Float64
+ kind = 47 and base = 2 and domain = TRealDomain() and realKind = 47 and extended = false
+ or
+ // _Float64x
+ kind = 48 and base = 2 and domain = TRealDomain() and realKind = 48 and extended = true
+ or
+ // _Float128
+ kind = 49 and base = 2 and domain = TRealDomain() and realKind = 49 and extended = false
+ or
+ // _Float128x
+ kind = 50 and base = 2 and domain = TRealDomain() and realKind = 50 and extended = true
+}
+
+/**
+ * The C/C++ floating point types. See 4.5. This includes `float`, `double` and `long double`, the
+ * fixed-size floating-point types like `_Float32`, the extended-precision floating-point types like
+ * `_Float64x`, and the decimal floating-point types like `_Decimal32`. It also includes the complex
+ * and imaginary versions of all of these types.
*/
class FloatingPointType extends ArithmeticType {
+ final int base;
+ final TypeDomain domain;
+ final int realKind;
+ final boolean extended;
+
FloatingPointType() {
exists(int kind |
builtintypes(underlyingElement(this), _, kind, _, _, _) and
- (
- kind >= 24 and kind <= 32
- or
- kind >= 38 and kind <= 42
- or
- kind >= 45 and kind <= 50
- )
+ floatingPointTypeMapping(kind, base, domain, realKind, extended)
)
}
+
+ /** Gets the numeric base of this type's representation: 2 (binary) or 10 (decimal). */
+ final int getBase() { result = base }
+
+ /**
+ * Gets the type domain of this type. Can be `RealDomain`, `ComplexDomain`, or `ImaginaryDomain`.
+ */
+ final TypeDomain getDomain() { result = domain }
+
+ /**
+ * Gets the corresponding real type of this type. For example, the corresponding real type of
+ * `_Complex double` is `double`.
+ */
+ final RealNumberType getRealType() {
+ builtintypes(unresolveElement(result), _, realKind, _, _, _)
+ }
+
+ /** Holds if this type is an extended precision floating-point type, such as `_Float32x`. */
+ final predicate isExtendedPrecision() { extended = true }
+}
+
+/**
+ * A floating-point type representing a real number.
+ */
+class RealNumberType extends FloatingPointType {
+ RealNumberType() { domain instanceof RealDomain }
+}
+
+/**
+ * A floating-point type representing a complex number.
+ */
+class ComplexNumberType extends FloatingPointType {
+ ComplexNumberType() { domain instanceof ComplexDomain }
+}
+
+/**
+ * A floating-point type representing an imaginary number.
+ */
+class ImaginaryNumberType extends FloatingPointType {
+ ImaginaryNumberType() { domain instanceof ImaginaryDomain }
+}
+
+/**
+ * A floating-point type whose representation is base 2.
+ */
+class BinaryFloatingPointType extends FloatingPointType {
+ BinaryFloatingPointType() { base = 2 }
+}
+
+/**
+ * A floating-point type whose representation is base 10.
+ */
+class DecimalFloatingPointType extends FloatingPointType {
+ DecimalFloatingPointType() { base = 10 }
}
/**
@@ -727,7 +886,7 @@ class FloatingPointType extends ArithmeticType {
* float f;
* ```
*/
-class FloatType extends FloatingPointType {
+class FloatType extends RealNumberType, BinaryFloatingPointType {
FloatType() { builtintypes(underlyingElement(this), _, 24, _, _, _) }
override string getCanonicalQLClass() { result = "FloatType" }
@@ -739,7 +898,7 @@ class FloatType extends FloatingPointType {
* double d;
* ```
*/
-class DoubleType extends FloatingPointType {
+class DoubleType extends RealNumberType, BinaryFloatingPointType {
DoubleType() { builtintypes(underlyingElement(this), _, 25, _, _, _) }
override string getCanonicalQLClass() { result = "DoubleType" }
@@ -751,7 +910,7 @@ class DoubleType extends FloatingPointType {
* long double ld;
* ```
*/
-class LongDoubleType extends FloatingPointType {
+class LongDoubleType extends RealNumberType, BinaryFloatingPointType {
LongDoubleType() { builtintypes(underlyingElement(this), _, 26, _, _, _) }
override string getCanonicalQLClass() { result = "LongDoubleType" }
@@ -763,7 +922,7 @@ class LongDoubleType extends FloatingPointType {
* __float128 f128;
* ```
*/
-class Float128Type extends FloatingPointType {
+class Float128Type extends RealNumberType, BinaryFloatingPointType {
Float128Type() { builtintypes(underlyingElement(this), _, 38, _, _, _) }
override string getCanonicalQLClass() { result = "Float128Type" }
@@ -775,7 +934,7 @@ class Float128Type extends FloatingPointType {
* _Decimal32 d32;
* ```
*/
-class Decimal32Type extends FloatingPointType {
+class Decimal32Type extends RealNumberType, DecimalFloatingPointType {
Decimal32Type() { builtintypes(underlyingElement(this), _, 40, _, _, _) }
override string getCanonicalQLClass() { result = "Decimal32Type" }
@@ -787,7 +946,7 @@ class Decimal32Type extends FloatingPointType {
* _Decimal64 d64;
* ```
*/
-class Decimal64Type extends FloatingPointType {
+class Decimal64Type extends RealNumberType, DecimalFloatingPointType {
Decimal64Type() { builtintypes(underlyingElement(this), _, 41, _, _, _) }
override string getCanonicalQLClass() { result = "Decimal64Type" }
@@ -799,7 +958,7 @@ class Decimal64Type extends FloatingPointType {
* _Decimal128 d128;
* ```
*/
-class Decimal128Type extends FloatingPointType {
+class Decimal128Type extends RealNumberType, DecimalFloatingPointType {
Decimal128Type() { builtintypes(underlyingElement(this), _, 42, _, _, _) }
override string getCanonicalQLClass() { result = "Decimal128Type" }
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll
index 833c929ecc5..f843a6414e5 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll
@@ -12,7 +12,9 @@ private newtype TIRType =
TIRBooleanType(int byteSize) { Language::hasBooleanType(byteSize) } or
TIRSignedIntegerType(int byteSize) { Language::hasSignedIntegerType(byteSize) } or
TIRUnsignedIntegerType(int byteSize) { Language::hasUnsignedIntegerType(byteSize) } or
- TIRFloatingPointType(int byteSize) { Language::hasFloatingPointType(byteSize) } or
+ TIRFloatingPointType(int byteSize, int base, Language::TypeDomain domain) {
+ Language::hasFloatingPointType(byteSize, base, domain)
+ } or
TIRAddressType(int byteSize) { Language::hasAddressType(byteSize) } or
TIRFunctionAddressType(int byteSize) { Language::hasFunctionAddressType(byteSize) } or
TIROpaqueType(Language::OpaqueTypeTag tag, int byteSize) {
@@ -104,7 +106,7 @@ private class IRSizedType extends IRType {
this = TIRBooleanType(byteSize) or
this = TIRSignedIntegerType(byteSize) or
this = TIRUnsignedIntegerType(byteSize) or
- this = TIRFloatingPointType(byteSize) or
+ this = TIRFloatingPointType(byteSize, _, _) or
this = TIRAddressType(byteSize) or
this = TIRFunctionAddressType(byteSize) or
this = TIROpaqueType(_, byteSize)
@@ -133,7 +135,7 @@ class IRNumericType extends IRSizedType {
IRNumericType() {
this = TIRSignedIntegerType(byteSize) or
this = TIRUnsignedIntegerType(byteSize) or
- this = TIRFloatingPointType(byteSize)
+ this = TIRFloatingPointType(byteSize, _, _)
}
}
@@ -171,14 +173,45 @@ class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType {
* A floating-point type.
*/
class IRFloatingPointType extends IRNumericType, TIRFloatingPointType {
- final override string toString() { result = "float" + byteSize.toString() }
+ private final int base;
+ private final Language::TypeDomain domain;
+
+ IRFloatingPointType() {
+ this = TIRFloatingPointType(_, base, domain)
+ }
+
+ final override string toString() {
+ result = getDomainPrefix() + getBaseString() + byteSize.toString()
+ }
final override Language::LanguageType getCanonicalLanguageType() {
- result = Language::getCanonicalFloatingPointType(byteSize)
+ result = Language::getCanonicalFloatingPointType(byteSize, base, domain)
}
pragma[noinline]
final override int getByteSize() { result = byteSize }
+
+ /** Gets the numeric base of the type. Can be either 2 (binary) or 10 (decimal). */
+ final int getBase() { result = base }
+
+ /**
+ * Gets the type domain of the type. Can be `RealDomain`, `ComplexDomain`, or `ImaginaryDomain`.
+ */
+ final Language::TypeDomain getDomain() { result = domain }
+
+ private string getBaseString() {
+ base = 2 and result = "float"
+ or
+ base = 10 and result = "decimal"
+ }
+
+ private string getDomainPrefix() {
+ domain instanceof Language::RealDomain and result = ""
+ or
+ domain instanceof Language::ComplexDomain and result = "c"
+ or
+ domain instanceof Language::ImaginaryDomain and result = "i"
+ }
}
/**
diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll
index 9e8044ede4f..42420f8f925 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll
@@ -86,9 +86,15 @@ predicate hasUnsignedIntegerType(int byteSize) {
}
/**
- * Holds if an `IRFloatingPointType` with the specified `byteSize` should exist.
+ * Holds if an `IRFloatingPointType` with the specified size, base, and type domain should exist.
*/
-predicate hasFloatingPointType(int byteSize) { byteSize = any(FloatingPointType type).getSize() }
+predicate hasFloatingPointType(int byteSize, int base, TypeDomain domain) {
+ exists(FloatingPointType type |
+ byteSize = type.getSize() and
+ base = type.getBase() and
+ domain = type.getDomain()
+ )
+}
private predicate isPointerIshType(Type type) {
type instanceof PointerType
@@ -159,8 +165,13 @@ private IRType getIRTypeForPRValue(Type type) {
isUnsignedIntegerType(unspecifiedType) and
result.(IRUnsignedIntegerType).getByteSize() = type.getSize()
or
- unspecifiedType instanceof FloatingPointType and
- result.(IRFloatingPointType).getByteSize() = type.getSize()
+ exists(FloatingPointType floatType, IRFloatingPointType irFloatType |
+ floatType = unspecifiedType and
+ irFloatType = result and
+ irFloatType.getByteSize() = floatType.getSize() and
+ irFloatType.getBase() = floatType.getBase() and
+ irFloatType.getDomain() = floatType.getDomain()
+ )
or
isPointerIshType(unspecifiedType) and result.(IRAddressType).getByteSize() = getTypeSize(type)
or
@@ -438,15 +449,30 @@ CppPRValueType getCanonicalUnsignedIntegerType(int byteSize) {
}
/**
- * Gets the `CppType` that is the canonical type for an `IRFloatingPointType` with the specified
- * `byteSize`.
+ * Gets the sort priority of a `RealNumberType` base on its precision.
*/
-CppPRValueType getCanonicalFloatingPointType(int byteSize) {
+private int getPrecisionPriority(RealNumberType type) {
+ // Prefer `double`, `float`, `long double` in that order.
+ if type instanceof DoubleType then result = 4
+ else if type instanceof FloatType then result = 3
+ else if type instanceof LongDoubleType then result = 2
+ // If we get this far, prefer non-extended-precision types.
+ else if not type.isExtendedPrecision() then result = 1
+ else result = 0
+}
+
+/**
+ * Gets the `CppType` that is the canonical type for an `IRFloatingPointType` with the specified
+ * size, base, and type domain.
+ */
+CppPRValueType getCanonicalFloatingPointType(int byteSize, int base, TypeDomain domain) {
result =
TPRValueType(max(FloatingPointType type |
- type.getSize() = byteSize
+ type.getSize() = byteSize and
+ type.getBase() = base and
+ type.getDomain() = domain
|
- type order by type.toString() desc
+ type order by getPrecisionPriority(type.getRealType()), type.toString() desc
))
}
diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll
index 6e88e711711..9268af428eb 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll
@@ -9,6 +9,11 @@ class LanguageType = CppType;
class OpaqueTypeTag = Cpp::Type;
+class TypeDomain = Cpp::TypeDomain;
+class RealDomain = Cpp::RealDomain;
+class ComplexDomain = Cpp::ComplexDomain;
+class ImaginaryDomain = Cpp::ImaginaryDomain;
+
class Function = Cpp::Function;
class Location = Cpp::Location;
diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
index abce5a6a19d..c01e93122a7 100644
--- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
+++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
@@ -234,6 +234,62 @@ clang.cpp:
# 6| 0: [VariableAccess] globalInt
# 6| Type = [IntType] int
# 6| ValueCategory = lvalue
+complex.c:
+# 1| [TopLevelFunction] void complex_math()
+# 1| params:
+# 1| body: [Block] { ... }
+# 2| 0: [DeclStmt] declaration
+# 2| 0: [VariableDeclarationEntry] definition of cf
+# 2| Type = [ArithmeticType] _Complex float
+# 2| init: [Initializer] initializer for cf
+# 2| expr: [CStyleCast] (_Complex float)...
+# 2| Conversion = [FloatingPointConversion] floating point conversion
+# 2| Type = [ArithmeticType] _Complex float
+# 2| ValueCategory = prvalue
+# 2| expr: [AddExpr] ... + ...
+# 2| Type = [ArithmeticType] _Complex double
+# 2| ValueCategory = prvalue
+# 2| 0: [CStyleCast] (_Complex double)...
+# 2| Conversion = [FloatingPointConversion] floating point conversion
+# 2| Type = [ArithmeticType] _Complex double
+# 2| ValueCategory = prvalue
+# 2| expr: [Literal] 2.0
+# 2| Type = [DoubleType] double
+# 2| Value = [Literal] 2.0
+# 2| ValueCategory = prvalue
+# 2| 1: [CStyleCast] (_Complex double)...
+# 2| Conversion = [FloatingPointConversion] floating point conversion
+# 2| Type = [ArithmeticType] _Complex double
+# 2| ValueCategory = prvalue
+# 2| expr: [Literal] (0.0,1.0i)
+# 2| Type = [ArithmeticType] _Complex float
+# 2| Value = [Literal] (0.0,1.0i)
+# 2| ValueCategory = prvalue
+# 3| 1: [DeclStmt] declaration
+# 3| 0: [VariableDeclarationEntry] definition of cf2
+# 3| Type = [ArithmeticType] _Complex float
+# 3| init: [Initializer] initializer for cf2
+# 3| expr: [MulExpr] ... * ...
+# 3| Type = [ArithmeticType] _Complex float
+# 3| ValueCategory = prvalue
+# 3| 0: [VariableAccess] cf
+# 3| Type = [ArithmeticType] _Complex float
+# 3| ValueCategory = prvalue(load)
+# 3| 1: [VariableAccess] cf
+# 3| Type = [ArithmeticType] _Complex float
+# 3| ValueCategory = prvalue(load)
+# 4| 2: [DeclStmt] declaration
+# 4| 0: [VariableDeclarationEntry] definition of d
+# 4| Type = [DoubleType] double
+# 4| init: [Initializer] initializer for d
+# 4| expr: [CStyleCast] (double)...
+# 4| Conversion = [FloatingPointConversion] floating point conversion
+# 4| Type = [DoubleType] double
+# 4| ValueCategory = prvalue
+# 4| expr: [VariableAccess] cf2
+# 4| Type = [ArithmeticType] _Complex float
+# 4| ValueCategory = prvalue(load)
+# 5| 3: [ReturnStmt] return ...
ir.cpp:
# 1| [TopLevelFunction] void Constants()
# 1| params:
diff --git a/cpp/ql/test/library-tests/ir/ir/complex.c b/cpp/ql/test/library-tests/ir/ir/complex.c
new file mode 100644
index 00000000000..51775832586
--- /dev/null
+++ b/cpp/ql/test/library-tests/ir/ir/complex.c
@@ -0,0 +1,5 @@
+void complex_math(void) {
+ _Complex float cf = 2.0 + 1.0if;
+ _Complex float cf2 = cf * cf;
+ double d = cf2;
+}
diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected
index e4bbac446ba..f5e5b0b250d 100644
--- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected
+++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected
@@ -124,6 +124,39 @@ clang.cpp:
# 5| v5_8(void) = AliasedUse : ~mu5_4
# 5| v5_9(void) = ExitFunction :
+complex.c:
+# 1| void complex_math()
+# 1| Block 0
+# 1| v1_1(void) = EnterFunction :
+# 1| mu1_2(unknown) = AliasedDefinition :
+# 1| mu1_3(unknown) = InitializeNonLocal :
+# 1| mu1_4(unknown) = UnmodeledDefinition :
+# 2| r2_1(glval<_Complex float>) = VariableAddress[cf] :
+# 2| r2_2(double) = Constant[2.0] :
+# 2| r2_3(_Complex double) = Convert : r2_2
+# 2| r2_4(_Complex float) = Constant[(0.0,1.0i)] :
+# 2| r2_5(_Complex double) = Convert : r2_4
+# 2| r2_6(_Complex double) = Add : r2_3, r2_5
+# 2| r2_7(_Complex float) = Convert : r2_6
+# 2| mu2_8(_Complex float) = Store : &:r2_1, r2_7
+# 3| r3_1(glval<_Complex float>) = VariableAddress[cf2] :
+# 3| r3_2(glval<_Complex float>) = VariableAddress[cf] :
+# 3| r3_3(_Complex float) = Load : &:r3_2, ~mu1_4
+# 3| r3_4(glval<_Complex float>) = VariableAddress[cf] :
+# 3| r3_5(_Complex float) = Load : &:r3_4, ~mu1_4
+# 3| r3_6(_Complex float) = Mul : r3_3, r3_5
+# 3| mu3_7(_Complex float) = Store : &:r3_1, r3_6
+# 4| r4_1(glval) = VariableAddress[d] :
+# 4| r4_2(glval<_Complex float>) = VariableAddress[cf2] :
+# 4| r4_3(_Complex float) = Load : &:r4_2, ~mu1_4
+# 4| r4_4(double) = Convert : r4_3
+# 4| mu4_5(double) = Store : &:r4_1, r4_4
+# 5| v5_1(void) = NoOp :
+# 1| v1_5(void) = ReturnVoid :
+# 1| v1_6(void) = UnmodeledUse : mu*
+# 1| v1_7(void) = AliasedUse : ~mu1_4
+# 1| v1_8(void) = ExitFunction :
+
ir.cpp:
# 1| void Constants()
# 1| Block 0
diff --git a/cpp/ql/test/library-tests/ir/types/complex.c b/cpp/ql/test/library-tests/ir/types/complex.c
new file mode 100644
index 00000000000..3766bde086a
--- /dev/null
+++ b/cpp/ql/test/library-tests/ir/types/complex.c
@@ -0,0 +1,6 @@
+void Complex(void) {
+ _Complex float cf; //$irtype=cfloat8
+ _Complex double cd; //$irtype=cfloat16
+ _Complex long double cld; //$irtype=cfloat32
+ // _Complex __float128 cf128;
+}
\ No newline at end of file
diff --git a/cpp/ql/test/library-tests/ir/types/irtypes.cpp b/cpp/ql/test/library-tests/ir/types/irtypes.cpp
new file mode 100644
index 00000000000..321382567b7
--- /dev/null
+++ b/cpp/ql/test/library-tests/ir/types/irtypes.cpp
@@ -0,0 +1,65 @@
+struct A {
+ int f_a;
+};
+
+struct B {
+ double f_a;
+ float f_b;
+};
+
+enum E {
+ Zero,
+ One,
+ Two,
+ Three
+};
+
+enum class ScopedE {
+ Zero,
+ One,
+ Two,
+ Three
+};
+
+void IRTypes() {
+ char c; //$irtype=int1
+ signed char sc; //$irtype=int1
+ unsigned char uc; //$irtype=uint1
+ short s; //$irtype=int2
+ signed short ss; //$irtype=int2
+ unsigned short us; //$irtype=uint2
+ int i; //$irtype=int4
+ signed int si; //$irtype=int4
+ unsigned int ui; //$irtype=uint4
+ long l; //$irtype=int8
+ signed long sl; //$irtype=int8
+ unsigned long ul; //$irtype=uint8
+ long long ll; //$irtype=int8
+ signed long long sll; //$irtype=int8
+ unsigned long long ull; //$irtype=uint8
+ bool b; //$irtype=bool1
+ float f; //$irtype=float4
+ double d; //$irtype=float8
+ long double ld; //$irtype=float16
+ __float128 f128; //$irtype=float16
+
+ wchar_t wc; //$irtype=uint4
+// char8_t c8; //$irtype=uint1
+ char16_t c16; //$irtype=uint2
+ char32_t c32; //$irtype=uint4
+
+ int* pi; //$irtype=addr8
+ int& ri = i; //$irtype=addr8
+ void (*pfn)() = nullptr; //$irtype=func8
+ void (&rfn)() = IRTypes; //$irtype=func8
+
+ A s_a; //$irtype=opaque4{A}
+ B s_b; //$irtype=opaque16{B}
+
+ E e; //$irtype=uint4
+ ScopedE se; //$irtype=uint4
+
+ B a_b[10]; //$irtype=opaque160{B[10]}
+}
+
+// semmle-extractor-options: -std=c++17 --clang
diff --git a/cpp/ql/test/library-tests/ir/types/irtypes.expected b/cpp/ql/test/library-tests/ir/types/irtypes.expected
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/cpp/ql/test/library-tests/ir/types/irtypes.ql b/cpp/ql/test/library-tests/ir/types/irtypes.ql
new file mode 100644
index 00000000000..ef103e40c5b
--- /dev/null
+++ b/cpp/ql/test/library-tests/ir/types/irtypes.ql
@@ -0,0 +1,18 @@
+private import cpp
+private import semmle.code.cpp.ir.implementation.raw.IR
+import TestUtilities.InlineExpectationsTest
+
+class IRTypesTest extends InlineExpectationsTest {
+ IRTypesTest() { this = "IRTypesTest" }
+
+ override string getARelevantTag() { result = "irtype" }
+
+ override predicate hasActualResult(Location location, string element, string tag, string value) {
+ exists(IRUserVariable irVar |
+ location = irVar.getLocation() and
+ element = irVar.toString() and
+ tag = "irtype" and
+ value = irVar.getIRType().toString()
+ )
+ }
+}
diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll
index 833c929ecc5..f843a6414e5 100644
--- a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll
+++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll
@@ -12,7 +12,9 @@ private newtype TIRType =
TIRBooleanType(int byteSize) { Language::hasBooleanType(byteSize) } or
TIRSignedIntegerType(int byteSize) { Language::hasSignedIntegerType(byteSize) } or
TIRUnsignedIntegerType(int byteSize) { Language::hasUnsignedIntegerType(byteSize) } or
- TIRFloatingPointType(int byteSize) { Language::hasFloatingPointType(byteSize) } or
+ TIRFloatingPointType(int byteSize, int base, Language::TypeDomain domain) {
+ Language::hasFloatingPointType(byteSize, base, domain)
+ } or
TIRAddressType(int byteSize) { Language::hasAddressType(byteSize) } or
TIRFunctionAddressType(int byteSize) { Language::hasFunctionAddressType(byteSize) } or
TIROpaqueType(Language::OpaqueTypeTag tag, int byteSize) {
@@ -104,7 +106,7 @@ private class IRSizedType extends IRType {
this = TIRBooleanType(byteSize) or
this = TIRSignedIntegerType(byteSize) or
this = TIRUnsignedIntegerType(byteSize) or
- this = TIRFloatingPointType(byteSize) or
+ this = TIRFloatingPointType(byteSize, _, _) or
this = TIRAddressType(byteSize) or
this = TIRFunctionAddressType(byteSize) or
this = TIROpaqueType(_, byteSize)
@@ -133,7 +135,7 @@ class IRNumericType extends IRSizedType {
IRNumericType() {
this = TIRSignedIntegerType(byteSize) or
this = TIRUnsignedIntegerType(byteSize) or
- this = TIRFloatingPointType(byteSize)
+ this = TIRFloatingPointType(byteSize, _, _)
}
}
@@ -171,14 +173,45 @@ class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType {
* A floating-point type.
*/
class IRFloatingPointType extends IRNumericType, TIRFloatingPointType {
- final override string toString() { result = "float" + byteSize.toString() }
+ private final int base;
+ private final Language::TypeDomain domain;
+
+ IRFloatingPointType() {
+ this = TIRFloatingPointType(_, base, domain)
+ }
+
+ final override string toString() {
+ result = getDomainPrefix() + getBaseString() + byteSize.toString()
+ }
final override Language::LanguageType getCanonicalLanguageType() {
- result = Language::getCanonicalFloatingPointType(byteSize)
+ result = Language::getCanonicalFloatingPointType(byteSize, base, domain)
}
pragma[noinline]
final override int getByteSize() { result = byteSize }
+
+ /** Gets the numeric base of the type. Can be either 2 (binary) or 10 (decimal). */
+ final int getBase() { result = base }
+
+ /**
+ * Gets the type domain of the type. Can be `RealDomain`, `ComplexDomain`, or `ImaginaryDomain`.
+ */
+ final Language::TypeDomain getDomain() { result = domain }
+
+ private string getBaseString() {
+ base = 2 and result = "float"
+ or
+ base = 10 and result = "decimal"
+ }
+
+ private string getDomainPrefix() {
+ domain instanceof Language::RealDomain and result = ""
+ or
+ domain instanceof Language::ComplexDomain and result = "c"
+ or
+ domain instanceof Language::ImaginaryDomain and result = "i"
+ }
}
/**
diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll
index cffe3d09f39..fdd7ef804d2 100644
--- a/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll
+++ b/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll
@@ -61,9 +61,13 @@ predicate hasUnsignedIntegerType(int byteSize) {
}
/**
- * Holds if an `IRFloatingPointType` with the specified `byteSize` should exist.
+ * Holds if an `IRFloatingPointType` with the specified size, base, and type domain should exist.
*/
-predicate hasFloatingPointType(int byteSize) { byteSize = any(FloatingPointType type).getSize() }
+predicate hasFloatingPointType(int byteSize, int base, Language::TypeDomain domain) {
+ byteSize = any(FloatingPointType type).getSize() and
+ base = 2 and
+ domain instanceof Language::RealDomain
+}
private predicate isPointerIshType(Type type) {
type instanceof PointerType or
@@ -314,9 +318,11 @@ CSharpPRValueType getCanonicalUnsignedIntegerType(int byteSize) {
/**
* Gets the `CSharpType` that is the canonical type for an `IRFloatingPointType` with the specified
- * `byteSize`.
+ * size, base, and type domain.
*/
-CSharpPRValueType getCanonicalFloatingPointType(int byteSize) {
+CSharpPRValueType getCanonicalFloatingPointType(int byteSize, int base, Language::TypeDomain domain) {
+ base = 2 and
+ domain instanceof Language::RealDomain and
result = TPRValueType(any(FloatingPointType type | type.getSize() = byteSize))
}
diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll
index a8fb448f8d0..24870f5635a 100644
--- a/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll
+++ b/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll
@@ -28,6 +28,43 @@ class IntegralType = CSharp::IntegralType;
class FloatingPointType = CSharp::FloatingPointType;
+private newtype TTypeDomain = TRealDomain()
+
+/**
+ * The type domain of a floating-point type. One of `RealDomain`, `ComplexDomain`, or
+ * `ImaginaryDomain`.
+ */
+class TypeDomain extends TTypeDomain {
+ string toString() { none() }
+}
+
+/**
+ * The type domain of a floating-point type that represents a real number.
+ */
+class RealDomain extends TypeDomain, TRealDomain {
+ final override string toString() { result = "real" }
+}
+
+/**
+ * The type domain of a floating-point type that represents a complex number. Not currently used in
+ * C#.
+ */
+class ComplexDomain extends TypeDomain {
+ ComplexDomain() { none() }
+
+ final override string toString() { result = "complex" }
+}
+
+/**
+ * The type domain of a floating-point type that represents an imaginary number. Not currently used
+ * in C#.
+ */
+class ImaginaryDomain extends TypeDomain {
+ ImaginaryDomain() { none() }
+
+ final override string toString() { result = "imaginary" }
+}
+
private newtype TClassDerivation =
// Note that this is the `Class` type exported from this module, not CSharp::Class.
MkClassDerivation(Class base, Class derived) { derived.getABaseType() = base }
From 048a33e1438cbb4dc46c37d668bc7872bbf3f367 Mon Sep 17 00:00:00 2001
From: luchua-bc
Date: Fri, 27 Mar 2020 19:40:00 -0400
Subject: [PATCH 0016/1298] Remove user ids from the check since they get
logged a lot and are less sensitive
---
java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql
index 4648eb3e5fd..a647af366ac 100644
--- a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql
+++ b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql
@@ -48,7 +48,7 @@ class CredentialSource extends DataFlow::ExprNode {
private string getACredentialRegex() {
result = "(?i).*pass(wd|word|code|phrase)(?!.*question).*" or
- result = "(?i).*(uid|uuid|puid|username|userid|url).*"
+ result = "(?i).*(username|url).*"
}
class SensitiveLoggingSink extends DataFlow::ExprNode {
From 39dd9b709926e8906df5674a1abd5225e2a97150 Mon Sep 17 00:00:00 2001
From: Dave Bartolomeo
Date: Fri, 27 Mar 2020 19:46:53 -0400
Subject: [PATCH 0017/1298] C++/C#: Fix formatting
---
cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll | 8 +++-----
cpp/ql/test/library-tests/ir/types/irtypes.ql | 2 +-
.../src/semmle/code/csharp/ir/implementation/IRType.qll | 8 +++-----
3 files changed, 7 insertions(+), 11 deletions(-)
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll
index f843a6414e5..9a75ca19154 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll
@@ -173,12 +173,10 @@ class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType {
* A floating-point type.
*/
class IRFloatingPointType extends IRNumericType, TIRFloatingPointType {
- private final int base;
- private final Language::TypeDomain domain;
+ final private int base;
+ final private Language::TypeDomain domain;
- IRFloatingPointType() {
- this = TIRFloatingPointType(_, base, domain)
- }
+ IRFloatingPointType() { this = TIRFloatingPointType(_, base, domain) }
final override string toString() {
result = getDomainPrefix() + getBaseString() + byteSize.toString()
diff --git a/cpp/ql/test/library-tests/ir/types/irtypes.ql b/cpp/ql/test/library-tests/ir/types/irtypes.ql
index ef103e40c5b..56a7666458b 100644
--- a/cpp/ql/test/library-tests/ir/types/irtypes.ql
+++ b/cpp/ql/test/library-tests/ir/types/irtypes.ql
@@ -10,7 +10,7 @@ class IRTypesTest extends InlineExpectationsTest {
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(IRUserVariable irVar |
location = irVar.getLocation() and
- element = irVar.toString() and
+ element = irVar.toString() and
tag = "irtype" and
value = irVar.getIRType().toString()
)
diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll
index f843a6414e5..9a75ca19154 100644
--- a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll
+++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll
@@ -173,12 +173,10 @@ class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType {
* A floating-point type.
*/
class IRFloatingPointType extends IRNumericType, TIRFloatingPointType {
- private final int base;
- private final Language::TypeDomain domain;
+ final private int base;
+ final private Language::TypeDomain domain;
- IRFloatingPointType() {
- this = TIRFloatingPointType(_, base, domain)
- }
+ IRFloatingPointType() { this = TIRFloatingPointType(_, base, domain) }
final override string toString() {
result = getDomainPrefix() + getBaseString() + byteSize.toString()
From 434e11c0c59b5d7cd17bb9e5be454a29b70f5e4e Mon Sep 17 00:00:00 2001
From: Dave Bartolomeo
Date: Fri, 27 Mar 2020 19:47:08 -0400
Subject: [PATCH 0018/1298] C++: Fix test output
---
.../variables/variables/types.expected | 26 +++++++++----------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/cpp/ql/test/library-tests/variables/variables/types.expected b/cpp/ql/test/library-tests/variables/variables/types.expected
index cdc8c42a762..9f5df340263 100644
--- a/cpp/ql/test/library-tests/variables/variables/types.expected
+++ b/cpp/ql/test/library-tests/variables/variables/types.expected
@@ -1,21 +1,21 @@
| ..()(..) | RoutineType | | | | |
| ..(*)(..) | FunctionPointerType | | ..()(..) | | |
-| _Complex __float128 | FloatingPointType | | | | |
-| _Complex double | FloatingPointType | | | | |
-| _Complex float | FloatingPointType | | | | |
-| _Complex long double | FloatingPointType | | | | |
+| _Complex __float128 | BinaryFloatingPointType, ComplexNumberType | | | | |
+| _Complex double | BinaryFloatingPointType, ComplexNumberType | | | | |
+| _Complex float | BinaryFloatingPointType, ComplexNumberType | | | | |
+| _Complex long double | BinaryFloatingPointType, ComplexNumberType | | | | |
| _Decimal32 | Decimal32Type | | | | |
| _Decimal64 | Decimal64Type | | | | |
| _Decimal128 | Decimal128Type | | | | |
-| _Float32 | FloatingPointType | | | | |
-| _Float32x | FloatingPointType | | | | |
-| _Float64 | FloatingPointType | | | | |
-| _Float64x | FloatingPointType | | | | |
-| _Float128 | FloatingPointType | | | | |
-| _Float128x | FloatingPointType | | | | |
-| _Imaginary double | FloatingPointType | | | | |
-| _Imaginary float | FloatingPointType | | | | |
-| _Imaginary long double | FloatingPointType | | | | |
+| _Float32 | BinaryFloatingPointType, RealNumberType | | | | |
+| _Float32x | BinaryFloatingPointType, RealNumberType | | | | |
+| _Float64 | BinaryFloatingPointType, RealNumberType | | | | |
+| _Float64x | BinaryFloatingPointType, RealNumberType | | | | |
+| _Float128 | BinaryFloatingPointType, RealNumberType | | | | |
+| _Float128x | BinaryFloatingPointType, RealNumberType | | | | |
+| _Imaginary double | BinaryFloatingPointType, ImaginaryNumberType | | | | |
+| _Imaginary float | BinaryFloatingPointType, ImaginaryNumberType | | | | |
+| _Imaginary long double | BinaryFloatingPointType, ImaginaryNumberType | | | | |
| __float128 | Float128Type | | | | |
| __int128 | Int128Type | | | | |
| __va_list_tag | DirectAccessHolder, MetricClass, Struct, StructLikeClass | | | | |
From 7fce4ce9d1c9a34494ad82b6da6c7ae36434b5f1 Mon Sep 17 00:00:00 2001
From: Mathias Vorreiter Pedersen
Date: Sat, 28 Mar 2020 12:34:05 +0100
Subject: [PATCH 0019/1298] Include join order fix from #3142
---
cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll | 1 +
cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll | 1 +
cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll | 1 +
cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll | 1 +
.../src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll | 1 +
cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll | 1 +
.../src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll | 1 +
.../src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll | 1 +
.../src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll | 1 +
.../ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll | 1 +
.../src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll | 1 +
.../src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll | 1 +
.../src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll | 1 +
.../src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll | 1 +
java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll | 1 +
java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll | 1 +
java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll | 1 +
java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll | 1 +
java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll | 1 +
19 files changed, 19 insertions(+)
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll
index f7f9b2a0393..7d2d728b67e 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll
@@ -548,6 +548,7 @@ private predicate throughFlowNodeCand(Node node, Configuration config) {
}
/** Holds if flow may return from `callable`. */
+pragma[nomagic]
private predicate returnFlowCallableCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll
index f7f9b2a0393..7d2d728b67e 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll
@@ -548,6 +548,7 @@ private predicate throughFlowNodeCand(Node node, Configuration config) {
}
/** Holds if flow may return from `callable`. */
+pragma[nomagic]
private predicate returnFlowCallableCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll
index f7f9b2a0393..7d2d728b67e 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll
@@ -548,6 +548,7 @@ private predicate throughFlowNodeCand(Node node, Configuration config) {
}
/** Holds if flow may return from `callable`. */
+pragma[nomagic]
private predicate returnFlowCallableCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll
index f7f9b2a0393..7d2d728b67e 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll
@@ -548,6 +548,7 @@ private predicate throughFlowNodeCand(Node node, Configuration config) {
}
/** Holds if flow may return from `callable`. */
+pragma[nomagic]
private predicate returnFlowCallableCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll
index f7f9b2a0393..7d2d728b67e 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll
@@ -548,6 +548,7 @@ private predicate throughFlowNodeCand(Node node, Configuration config) {
}
/** Holds if flow may return from `callable`. */
+pragma[nomagic]
private predicate returnFlowCallableCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll
index f7f9b2a0393..7d2d728b67e 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll
@@ -548,6 +548,7 @@ private predicate throughFlowNodeCand(Node node, Configuration config) {
}
/** Holds if flow may return from `callable`. */
+pragma[nomagic]
private predicate returnFlowCallableCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll
index f7f9b2a0393..7d2d728b67e 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll
@@ -548,6 +548,7 @@ private predicate throughFlowNodeCand(Node node, Configuration config) {
}
/** Holds if flow may return from `callable`. */
+pragma[nomagic]
private predicate returnFlowCallableCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll
index f7f9b2a0393..7d2d728b67e 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll
@@ -548,6 +548,7 @@ private predicate throughFlowNodeCand(Node node, Configuration config) {
}
/** Holds if flow may return from `callable`. */
+pragma[nomagic]
private predicate returnFlowCallableCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll
index f7f9b2a0393..7d2d728b67e 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll
@@ -548,6 +548,7 @@ private predicate throughFlowNodeCand(Node node, Configuration config) {
}
/** Holds if flow may return from `callable`. */
+pragma[nomagic]
private predicate returnFlowCallableCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll
index f7f9b2a0393..7d2d728b67e 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll
@@ -548,6 +548,7 @@ private predicate throughFlowNodeCand(Node node, Configuration config) {
}
/** Holds if flow may return from `callable`. */
+pragma[nomagic]
private predicate returnFlowCallableCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll
index f7f9b2a0393..7d2d728b67e 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll
@@ -548,6 +548,7 @@ private predicate throughFlowNodeCand(Node node, Configuration config) {
}
/** Holds if flow may return from `callable`. */
+pragma[nomagic]
private predicate returnFlowCallableCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll
index f7f9b2a0393..7d2d728b67e 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll
@@ -548,6 +548,7 @@ private predicate throughFlowNodeCand(Node node, Configuration config) {
}
/** Holds if flow may return from `callable`. */
+pragma[nomagic]
private predicate returnFlowCallableCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll
index f7f9b2a0393..7d2d728b67e 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll
@@ -548,6 +548,7 @@ private predicate throughFlowNodeCand(Node node, Configuration config) {
}
/** Holds if flow may return from `callable`. */
+pragma[nomagic]
private predicate returnFlowCallableCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll
index f7f9b2a0393..7d2d728b67e 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll
@@ -548,6 +548,7 @@ private predicate throughFlowNodeCand(Node node, Configuration config) {
}
/** Holds if flow may return from `callable`. */
+pragma[nomagic]
private predicate returnFlowCallableCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll
index f7f9b2a0393..7d2d728b67e 100644
--- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll
+++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll
@@ -548,6 +548,7 @@ private predicate throughFlowNodeCand(Node node, Configuration config) {
}
/** Holds if flow may return from `callable`. */
+pragma[nomagic]
private predicate returnFlowCallableCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll
index f7f9b2a0393..7d2d728b67e 100644
--- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll
+++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll
@@ -548,6 +548,7 @@ private predicate throughFlowNodeCand(Node node, Configuration config) {
}
/** Holds if flow may return from `callable`. */
+pragma[nomagic]
private predicate returnFlowCallableCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll
index f7f9b2a0393..7d2d728b67e 100644
--- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll
+++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll
@@ -548,6 +548,7 @@ private predicate throughFlowNodeCand(Node node, Configuration config) {
}
/** Holds if flow may return from `callable`. */
+pragma[nomagic]
private predicate returnFlowCallableCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll
index f7f9b2a0393..7d2d728b67e 100644
--- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll
+++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll
@@ -548,6 +548,7 @@ private predicate throughFlowNodeCand(Node node, Configuration config) {
}
/** Holds if flow may return from `callable`. */
+pragma[nomagic]
private predicate returnFlowCallableCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll
index f7f9b2a0393..7d2d728b67e 100644
--- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll
+++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll
@@ -548,6 +548,7 @@ private predicate throughFlowNodeCand(Node node, Configuration config) {
}
/** Holds if flow may return from `callable`. */
+pragma[nomagic]
private predicate returnFlowCallableCand(
DataFlowCallable callable, ReturnKindExt kind, Configuration config
) {
From 000d894d994afd210a8e21df195c66c79143dad8 Mon Sep 17 00:00:00 2001
From: luchua-bc
Date: Sat, 28 Mar 2020 14:00:28 -0400
Subject: [PATCH 0020/1298] Include Gradle Logging
---
java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql
index a647af366ac..2e583bbb4d8 100644
--- a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql
+++ b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql
@@ -16,7 +16,7 @@ import PathGraph
class LoggerType extends RefType {
LoggerType() {
this.hasQualifiedName("org.apache.log4j", "Category") or //Log4J
- this.hasQualifiedName("org.slf4j", "Logger") //SLF4j
+ this.hasQualifiedName("org.slf4j", "Logger") //SLF4j and Gradle Logging
}
}
From 6b24e3c8be07368d82a2465217175e65b0d8c1e9 Mon Sep 17 00:00:00 2001
From: Dave Bartolomeo
Date: Sun, 29 Mar 2020 08:18:05 -0400
Subject: [PATCH 0021/1298] C++: Fix formatting
---
cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll | 3 +++
1 file changed, 3 insertions(+)
diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll
index 9268af428eb..f047d6c4753 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll
@@ -10,8 +10,11 @@ class LanguageType = CppType;
class OpaqueTypeTag = Cpp::Type;
class TypeDomain = Cpp::TypeDomain;
+
class RealDomain = Cpp::RealDomain;
+
class ComplexDomain = Cpp::ComplexDomain;
+
class ImaginaryDomain = Cpp::ImaginaryDomain;
class Function = Cpp::Function;
From f55005a0ec93d1dd0f3dcd94fea888e376b52c6f Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Mon, 30 Mar 2020 10:19:04 +0200
Subject: [PATCH 0022/1298] more precise warning message for implicit
string/number conversions
---
.../Expressions/ImplicitOperandConversion.ql | 21 ++++++++++++++++++-
.../ImplicitOperandConversion.expected | 4 +++-
.../ImplicitOperandConversion/tst.js | 3 +++
3 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/javascript/ql/src/Expressions/ImplicitOperandConversion.ql b/javascript/ql/src/Expressions/ImplicitOperandConversion.ql
index f26654517e5..c9cb618626a 100644
--- a/javascript/ql/src/Expressions/ImplicitOperandConversion.ql
+++ b/javascript/ql/src/Expressions/ImplicitOperandConversion.ql
@@ -162,7 +162,26 @@ abstract class NullOrUndefinedConversion extends ImplicitConversion {
class PlusConversion extends NullOrUndefinedConversion {
PlusConversion() { parent instanceof AddExpr or parent instanceof AssignAddExpr }
- override string getConversionTarget() { result = "number or string" }
+ override string getConversionTarget() {
+ result = getDefiniteCousinType()
+ or
+ not exists(getDefiniteCousinType()) and
+ result = "number or string"
+ }
+
+ /**
+ * Gets the cousin of this implicit conversion.
+ * E.g. if this is `a` in the expression `a + b`, then the cousin is `b`.
+ */
+ private Expr getCousin() { result = parent.getAChild() and not result = this.getEnclosingExpr() }
+
+ /**
+ * Gets the unique type of the cousin expression, if that type is `string` or `number`.
+ */
+ private string getDefiniteCousinType() {
+ result = unique(InferredType t | t = getCousin().flow().analyze().getAType()).getTypeofTag() and
+ result = ["string", "number"]
+ }
}
/**
diff --git a/javascript/ql/test/query-tests/Expressions/ImplicitOperandConversion/ImplicitOperandConversion.expected b/javascript/ql/test/query-tests/Expressions/ImplicitOperandConversion/ImplicitOperandConversion.expected
index 180a968b487..c99f2daf6ef 100644
--- a/javascript/ql/test/query-tests/Expressions/ImplicitOperandConversion/ImplicitOperandConversion.expected
+++ b/javascript/ql/test/query-tests/Expressions/ImplicitOperandConversion/ImplicitOperandConversion.expected
@@ -3,7 +3,7 @@
| tst.js:20:6:20:13 | 'string' | This expression will be implicitly converted from string to object. |
| tst.js:26:13:26:53 | "Settin ... o '%s'" | This expression will be implicitly converted from string to number. |
| tst.js:29:18:29:26 | !callback | This expression will be implicitly converted from boolean to object. |
-| tst.js:53:5:53:10 | void 0 | This expression will be implicitly converted from undefined to number or string. |
+| tst.js:53:5:53:10 | void 0 | This expression will be implicitly converted from undefined to number. |
| tst.js:61:3:61:3 | x | This expression will be implicitly converted from undefined to number. |
| tst.js:67:8:67:8 | y | This expression will be implicitly converted from undefined to number. |
| tst.js:73:5:73:5 | x | This expression will be implicitly converted from undefined to number. |
@@ -11,3 +11,5 @@
| tst.js:85:3:85:3 | x | This expression will be implicitly converted from undefined to number. |
| tst.js:100:5:100:7 | f() | This expression will be implicitly converted from undefined to number. |
| tst.js:106:5:106:7 | g() | This expression will be implicitly converted from undefined to number. |
+| tst.js:109:13:109:15 | g() | This expression will be implicitly converted from undefined to number. |
+| tst.js:110:13:110:15 | g() | This expression will be implicitly converted from undefined to string. |
diff --git a/javascript/ql/test/query-tests/Expressions/ImplicitOperandConversion/tst.js b/javascript/ql/test/query-tests/Expressions/ImplicitOperandConversion/tst.js
index a454ed9bde3..d5b523ecc3e 100644
--- a/javascript/ql/test/query-tests/Expressions/ImplicitOperandConversion/tst.js
+++ b/javascript/ql/test/query-tests/Expressions/ImplicitOperandConversion/tst.js
@@ -105,5 +105,8 @@ function l() {
}
g()|0;
g();
+
+ var a = g() + 2;
+ var b = g() + "str";
});
From a02213e7452bf9832174db524e2a98f127851184 Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Tue, 31 Mar 2020 11:14:58 +0200
Subject: [PATCH 0023/1298] change LoadStoreStep such that it can store in
different property
---
javascript/ql/src/semmle/javascript/Promises.qll | 8 +++++++-
.../semmle/javascript/dataflow/TypeTracking.qll | 8 ++++++--
.../javascript/dataflow/internal/StepSummary.qll | 16 ++++++++++++++--
3 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/javascript/ql/src/semmle/javascript/Promises.qll b/javascript/ql/src/semmle/javascript/Promises.qll
index 56025b75ffb..87a804dd113 100644
--- a/javascript/ql/src/semmle/javascript/Promises.qll
+++ b/javascript/ql/src/semmle/javascript/Promises.qll
@@ -176,7 +176,7 @@ module PromiseTypeTracking {
summary = StoreStep(field) and
step.store(pred, result, field)
or
- summary = LoadStoreStep(field) and
+ summary = LoadStoreStep(field, field) and
step.loadStore(pred, result, field)
)
}
@@ -246,6 +246,12 @@ abstract private class PromiseFlowStep extends DataFlow::AdditionalFlowStep {
final override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
this.loadStore(pred, succ, prop)
}
+
+ final override predicate loadStoreStep(
+ DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp
+ ) {
+ none()
+ }
}
/**
diff --git a/javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll
index 4edd1451a5b..57808e9c551 100644
--- a/javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll
+++ b/javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll
@@ -53,7 +53,9 @@ class TypeTracker extends TTypeTracker {
TypeTracker append(StepSummary step) {
step = LevelStep() and result = this
or
- step = LoadStoreStep(prop) and result = this
+ exists(string toProp | step = LoadStoreStep(prop, toProp) |
+ result = MkTypeTracker(hasCall, toProp)
+ )
or
step = CallStep() and result = MkTypeTracker(true, prop)
or
@@ -213,7 +215,9 @@ class TypeBackTracker extends TTypeBackTracker {
TypeBackTracker prepend(StepSummary step) {
step = LevelStep() and result = this
or
- step = LoadStoreStep(prop) and result = this
+ exists(string fromProp | step = LoadStoreStep(fromProp, prop) |
+ result = MkTypeBackTracker(hasReturn, fromProp)
+ )
or
step = CallStep() and hasReturn = false and result = this
or
diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll
index 25f8fb356fb..67c51ff975c 100644
--- a/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll
+++ b/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll
@@ -24,6 +24,11 @@ class OptionalPropertyName extends string {
abstract class TypeTrackingPseudoProperty extends string {
bindingset[this]
TypeTrackingPseudoProperty() { any() }
+
+ /**
+ * Gets a property name that `this` can be copied to in a `LoadStoreStep(this, result)`.
+ */
+ string getLoadStoreToProp() { none() }
}
/**
@@ -35,7 +40,12 @@ newtype TStepSummary =
ReturnStep() or
StoreStep(PropertyName prop) or
LoadStep(PropertyName prop) or
- LoadStoreStep(PropertyName prop)
+ LoadStoreStep(PropertyName fromProp, PropertyName toProp) {
+ fromProp = toProp or
+ exists(TypeTrackingPseudoProperty prop |
+ fromProp = prop and toProp = prop.getLoadStoreToProp()
+ )
+ }
/**
* INTERNAL: Use `TypeTracker` or `TypeBackTracker` instead.
@@ -55,7 +65,9 @@ class StepSummary extends TStepSummary {
or
exists(string prop | this = LoadStep(prop) | result = "load " + prop)
or
- exists(string prop | this = LoadStoreStep(prop) | result = "in " + prop)
+ exists(string fromProp, string toProp | this = LoadStoreStep(fromProp, toProp) |
+ result = "copy " + fromProp + " to " + toProp
+ )
}
}
From 25aea900b6776d68855d19d27d105cdd92b1a4db Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Tue, 31 Mar 2020 11:18:39 +0200
Subject: [PATCH 0024/1298] add more dataflow steps for Arrays
---
.../ql/src/semmle/javascript/Arrays.qll | 67 ++++++++++++++++++-
.../javascript/dataflow/Configuration.qll | 16 +++++
.../src/semmle/javascript/dataflow/Nodes.qll | 10 +++
.../library-tests/Arrays/DataFlow.expected | 4 ++
.../ql/test/library-tests/Arrays/arrays.js | 18 +++++
5 files changed, 112 insertions(+), 3 deletions(-)
diff --git a/javascript/ql/src/semmle/javascript/Arrays.qll b/javascript/ql/src/semmle/javascript/Arrays.qll
index c67e2277f69..34dafbb5a53 100644
--- a/javascript/ql/src/semmle/javascript/Arrays.qll
+++ b/javascript/ql/src/semmle/javascript/Arrays.qll
@@ -96,10 +96,55 @@ module ArrayTaintTracking {
* Classes and predicates for modelling data-flow for arrays.
*/
private module ArrayDataFlow {
+ private import DataFlow::PseudoProperties
+
/**
- * Gets a pseudo-field representing an element inside an array.
+ * A step modelling the creation of an Array using the `Array.from(x)` method.
+ * The step copies the elements of the argument (set, array, or iterator elements) into the resulting array.
*/
- private string arrayElement() { result = "$arrayElement$" }
+ private class ArrayFrom extends DataFlow::AdditionalFlowStep, DataFlow::CallNode {
+ ArrayFrom() { this = DataFlow::globalVarRef("Array").getAMemberCall("from") }
+
+ override predicate loadStoreStep(
+ DataFlow::Node pred, DataFlow::Node succ, string fromProp, string toProp
+ ) {
+ pred = this.getArgument(0) and
+ succ = this and
+ fromProp = arrayLikeElement() and
+ toProp = arrayElement()
+ }
+ }
+
+ /**
+ * A step modelling an array copy where the spread operator is used.
+ * The result is essentially array concatenation.
+ *
+ * Such a step can occur both with the `push` and `unshift` methods, or when creating a new array.
+ */
+ private class ArrayCopySpread extends DataFlow::AdditionalFlowStep {
+ DataFlow::Node spreadArgument; // the spread argument containing the elements to be copied.
+ DataFlow::Node base; // the object where the elements should be copied to.
+
+ ArrayCopySpread() {
+ exists(DataFlow::MethodCallNode mcn | mcn = this |
+ mcn.getMethodName() = ["push", "unshift"] and
+ spreadArgument = mcn.getASpreadArgument() and
+ base = mcn.getReceiver().getALocalSource()
+ )
+ or
+ spreadArgument = this.(DataFlow::ArrayCreationNode).getASpreadArgument() and
+ base = this
+ }
+
+ override predicate loadStoreStep(
+ DataFlow::Node pred, DataFlow::Node succ, string fromProp, string toProp
+ ) {
+ pred = spreadArgument and
+ succ = base and
+ fromProp = arrayLikeElement() and
+ toProp = arrayElement()
+ }
+ }
/**
* A step for storing an element on an array using `arr.push(e)` or `arr.unshift(e)`.
@@ -112,7 +157,7 @@ private module ArrayDataFlow {
override predicate storeStep(DataFlow::Node element, DataFlow::Node obj, string prop) {
prop = arrayElement() and
- (element = this.getAnArgument() or element = this.getASpreadArgument()) and
+ element = this.getAnArgument() and
obj = this.getReceiver().getALocalSource()
}
}
@@ -260,4 +305,20 @@ private module ArrayDataFlow {
succ = this
}
}
+
+ /**
+ * A step for modelling `for of` iteration on arrays.
+ */
+ private class ForOfStep extends DataFlow::AdditionalFlowStep, DataFlow::ValueNode {
+ ForOfStmt forOf;
+ DataFlow::Node element;
+
+ ForOfStep() { this.asExpr() = forOf.getIterationDomain() }
+
+ override predicate loadStep(DataFlow::Node obj, DataFlow::Node e, string prop) {
+ obj = this and
+ e = DataFlow::lvalueNode(forOf.getLValue()) and
+ prop = arrayElement()
+ }
+ }
}
diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll
index 1406c19a518..35fbac21d36 100644
--- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll
+++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll
@@ -574,6 +574,22 @@ abstract class AdditionalFlowStep extends DataFlow::Node {
}
}
+/**
+ * A collection of pseudo-properties that are used in multiple files.
+ * For use with load/store steps in `DataFlow::AdditionalFlowStep` and TypeTracking.
+ */
+module PseudoProperties {
+ /**
+ * Gets a pseudo-field representing an elements inside an `Array`.
+ */
+ string arrayElement() { result = "$arrayElement$" }
+
+ /**
+ * Gets a pseudo-property representing elements inside some array-like object.
+ */
+ string arrayLikeElement() { result = arrayElement() }
+}
+
/**
* A data flow node that should be considered a source for some specific configuration,
* in addition to any other sources that configuration may recognize.
diff --git a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll
index 4249c273a78..1a618db856e 100644
--- a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll
+++ b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll
@@ -620,6 +620,16 @@ class ArrayCreationNode extends DataFlow::ValueNode, DataFlow::SourceNode {
result = this.(ArrayLiteralNode).getSize() or
result = this.(ArrayConstructorInvokeNode).getSize()
}
+
+ /**
+ * Gets a data flow node corresponding to an array of values being passed as
+ * individual arguments to this array creation.
+ */
+ DataFlow::Node getASpreadArgument() {
+ exists(SpreadElement arg | arg = getAnElement().getEnclosingExpr() |
+ result = DataFlow::valueNode(arg.getOperand())
+ )
+ }
}
/**
diff --git a/javascript/ql/test/library-tests/Arrays/DataFlow.expected b/javascript/ql/test/library-tests/Arrays/DataFlow.expected
index e885315c287..158a49cece1 100644
--- a/javascript/ql/test/library-tests/Arrays/DataFlow.expected
+++ b/javascript/ql/test/library-tests/Arrays/DataFlow.expected
@@ -3,6 +3,10 @@
| arrays.js:2:16:2:23 | "source" | arrays.js:15:27:15:27 | e |
| arrays.js:2:16:2:23 | "source" | arrays.js:16:23:16:23 | e |
| arrays.js:2:16:2:23 | "source" | arrays.js:20:8:20:16 | arr.pop() |
+| arrays.js:2:16:2:23 | "source" | arrays.js:52:10:52:10 | x |
+| arrays.js:2:16:2:23 | "source" | arrays.js:56:10:56:10 | x |
+| arrays.js:2:16:2:23 | "source" | arrays.js:60:10:60:10 | x |
+| arrays.js:2:16:2:23 | "source" | arrays.js:66:10:66:10 | x |
| arrays.js:18:22:18:29 | "source" | arrays.js:18:50:18:50 | e |
| arrays.js:22:15:22:22 | "source" | arrays.js:23:8:23:17 | arr2.pop() |
| arrays.js:25:15:25:22 | "source" | arrays.js:26:8:26:17 | arr3.pop() |
diff --git a/javascript/ql/test/library-tests/Arrays/arrays.js b/javascript/ql/test/library-tests/Arrays/arrays.js
index 04c50100623..9837d9c5306 100644
--- a/javascript/ql/test/library-tests/Arrays/arrays.js
+++ b/javascript/ql/test/library-tests/Arrays/arrays.js
@@ -47,4 +47,22 @@
});
sink(arr[0]); // OK - tuple like usage.
+
+ for (const x of arr) {
+ sink(x); // NOT OK
+ }
+
+ for (const x of Array.from(arr)) {
+ sink(x); // NOT OK
+ }
+
+ for (const x of [...arr]) {
+ sink(x); // NOT OK
+ }
+
+ var arr7 = [];
+ arr7.push(...arr);
+ for (const x of arr7) {
+ sink(x); // NOT OK
+ }
});
From 546431c83d321fc23eabf762f0626eadf99c55ed Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Tue, 31 Mar 2020 11:19:28 +0200
Subject: [PATCH 0025/1298] dataflow and typetracking steps for Maps and Sets
---
javascript/ql/src/javascript.qll | 1 +
.../ql/src/semmle/javascript/MapAndSet.qll | 273 ++++++++++++++++++
.../javascript/dataflow/Configuration.qll | 39 ++-
.../frameworks/Sets/test.expected | 26 ++
.../library-tests/frameworks/Sets/test.ql | 32 ++
.../test/library-tests/frameworks/Sets/tst.js | 56 ++++
6 files changed, 425 insertions(+), 2 deletions(-)
create mode 100644 javascript/ql/src/semmle/javascript/MapAndSet.qll
create mode 100644 javascript/ql/test/library-tests/frameworks/Sets/test.expected
create mode 100644 javascript/ql/test/library-tests/frameworks/Sets/test.ql
create mode 100644 javascript/ql/test/library-tests/frameworks/Sets/tst.js
diff --git a/javascript/ql/src/javascript.qll b/javascript/ql/src/javascript.qll
index 4b4e1a5e04f..37a93dbf618 100644
--- a/javascript/ql/src/javascript.qll
+++ b/javascript/ql/src/javascript.qll
@@ -36,6 +36,7 @@ import semmle.javascript.JsonParsers
import semmle.javascript.JSX
import semmle.javascript.Lines
import semmle.javascript.Locations
+import semmle.javascript.MapAndSet
import semmle.javascript.Modules
import semmle.javascript.NodeJS
import semmle.javascript.NPM
diff --git a/javascript/ql/src/semmle/javascript/MapAndSet.qll b/javascript/ql/src/semmle/javascript/MapAndSet.qll
new file mode 100644
index 00000000000..aed3fe377a4
--- /dev/null
+++ b/javascript/ql/src/semmle/javascript/MapAndSet.qll
@@ -0,0 +1,273 @@
+import javascript
+private import semmle.javascript.dataflow.internal.StepSummary
+private import DataFlow::PseudoProperties
+
+/**
+ * Common predicates and classes for type and data-flow tracking on Maps and Sets.
+ */
+private module MapsAndSets {
+ /**
+ * An `AdditionalFlowStep` used to model a data-flow step related to Maps and Sets.
+ *
+ * The `loadStep`/`storeStep`/`loadStoreStep` methods are overloaded such that the new predicates
+ * `load`/`store`/`loadStore` can be used in the `MapsAndSetsTypeTracking` module.
+ * (Thereby avoiding conflicts with a "cousin" `AdditionalFlowStep` implementation.)
+ */
+ abstract class MapOrSetFlowStep extends DataFlow::AdditionalFlowStep {
+ final override predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() }
+
+ final override predicate step(
+ DataFlow::Node p, DataFlow::Node s, DataFlow::FlowLabel pl, DataFlow::FlowLabel sl
+ ) {
+ none()
+ }
+
+ /**
+ * Holds if the property `prop` of the object `pred` should be loaded into `succ`.
+ */
+ predicate load(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
+
+ final override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
+ this.load(pred, succ, prop)
+ }
+
+ /**
+ * Holds if `pred` should be stored in the object `succ` under the property `prop`.
+ */
+ predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
+
+ final override predicate storeStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
+ this.store(pred, succ, prop)
+ }
+
+ /**
+ * Holds if the property `prop` should be copied from the object `pred` to the object `succ`.
+ */
+ predicate loadStore(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
+
+ final override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
+ this.loadStore(pred, succ, prop, prop)
+ }
+
+ /**
+ * Holds if the property `loadProp` should be copied from the object `pred` to the property `storeProp` of object `succ`.
+ */
+ predicate loadStore(DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp) {
+ none()
+ }
+
+ final override predicate loadStoreStep(
+ DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp
+ ) {
+ this.loadStore(pred, succ, loadProp, storeProp)
+ }
+
+ /**
+ * Holds if this is a map step that could potentially load a value where the corresponding key has a known string value.
+ */
+ predicate canLoadKnownKey() { none() }
+ }
+}
+
+/**
+ * A collection of predicates and clases for type-tracking Maps and Sets.
+ */
+module MapsAndSetsTypeTracking {
+ private import MapsAndSets
+
+ /**
+ * Gets the result from a single step through a Map or Set, from `pred` to `result` summarized by `summary`.
+ */
+ pragma[inline]
+ DataFlow::SourceNode mapOrSetStep(DataFlow::Node pred, StepSummary summary) {
+ exists(MapOrSetFlowStep step, string field |
+ summary = LoadStep(field) and
+ step.load(pred, result, field) and
+ (not step.canLoadKnownKey() or not field = mapValueUnknownKey()) // for a step that could load a known key, we prune the steps where the key is unknown.
+ or
+ summary = StoreStep(field) and
+ step.store(pred, result, field)
+ or
+ exists(string toField | summary = LoadStoreStep(field, toField) |
+ field = toField and
+ step.loadStore(pred, result, field)
+ or
+ step.loadStore(pred, result, field, toField)
+ )
+ )
+ }
+
+ /**
+ * Gets the result from a single step through a Map or set, from `pred` with tracker `t2` to `result` with tracker `t`.
+ */
+ pragma[inline]
+ DataFlow::SourceNode mapOrSetStep(
+ DataFlow::SourceNode pred, DataFlow::TypeTracker t, DataFlow::TypeTracker t2
+ ) {
+ exists(DataFlow::Node mid, StepSummary summary | pred.flowsTo(mid) and t = t2.append(summary) |
+ result = mapOrSetStep(mid, summary)
+ )
+ }
+
+ /**
+ * A class enabling the use of the Map and Set related pseudo-properties as a pseudo-property in type-tracking predicates.
+ */
+ private class MapRelatedPseudoFieldAsTypeTrackingProperty extends TypeTrackingPseudoProperty {
+ MapRelatedPseudoFieldAsTypeTrackingProperty() {
+ this = [setElement(), iteratorElement()] or
+ any(MapOrSetFlowStep step).store(_, _, this)
+ }
+
+ override string getLoadStoreToProp() {
+ exists(MapOrSetFlowStep step | step.loadStore(_, _, this, result))
+ }
+ }
+}
+
+/**
+ * A module for data-flow steps related to `Set` and `Map`.
+ */
+private module MapAndSetDataFlow {
+ private import MapsAndSets
+
+ /**
+ * A step for an `add` method, which adds an element to a Set.
+ */
+ private class SetAdd extends MapOrSetFlowStep, DataFlow::MethodCallNode {
+ SetAdd() { this.getMethodName() = "add" }
+
+ override predicate store(DataFlow::Node element, DataFlow::Node obj, string prop) {
+ obj = this.getReceiver().getALocalSource() and
+ element = this.getArgument(0) and
+ prop = setElement()
+ }
+ }
+
+ /**
+ * A step for the `Set` constructor, which copies any elements from the first argument into the resulting set.
+ */
+ private class SetConstructor extends MapOrSetFlowStep, DataFlow::NewNode {
+ SetConstructor() { this = DataFlow::globalVarRef("Set").getAnInstantiation() }
+
+ override predicate loadStore(
+ DataFlow::Node pred, DataFlow::Node succ, string fromProp, string toProp
+ ) {
+ pred = this.getArgument(0) and
+ succ = this and
+ fromProp = arrayLikeElement() and
+ toProp = setElement()
+ }
+ }
+
+ /**
+ * A step for a `for of` statement on a Map, Set, or Iterator.
+ * For Sets and iterators the l-value are the elements of the set/iterator.
+ * For Maps the l-value is a tuple containing a key and a value.
+ *
+ * This is partially duplicated behavior with the `for of` step for Arrays (in Arrays.qll).
+ * This duplication is required for the type-tracking steps defined in `MapsAndSetsTypeTracking`.
+ */
+ private class ForOfStep extends MapOrSetFlowStep, DataFlow::ValueNode {
+ ForOfStmt forOf;
+ DataFlow::Node element;
+
+ ForOfStep() {
+ this.asExpr() = forOf.getIterationDomain() and
+ element = DataFlow::lvalueNode(forOf.getLValue())
+ }
+
+ override predicate load(DataFlow::Node obj, DataFlow::Node e, string prop) {
+ obj = this and
+ e = element and
+ prop = arrayLikeElement()
+ }
+
+ override predicate loadStore(
+ DataFlow::Node pred, DataFlow::Node succ, string fromProp, string toProp
+ ) {
+ pred = this and
+ succ = element and
+ fromProp = mapValueUnknownKey() and
+ toProp = "1"
+ }
+ }
+
+ /**
+ * A step for a call to `forEach` on a Set or Map.
+ */
+ private class SetMapForEach extends MapOrSetFlowStep, DataFlow::MethodCallNode {
+ SetMapForEach() { this.getMethodName() = "forEach" }
+
+ override predicate load(DataFlow::Node obj, DataFlow::Node element, string prop) {
+ obj = this.getReceiver() and
+ element = this.getCallback(0).getParameter(0) and
+ prop = [setElement(), mapValueUnknownKey()]
+ }
+ }
+
+ /**
+ * A call to the `get` method on a Map.
+ * If the key of the call to `get` has a known string value, then only the value corresponding to that key will be retrieved.
+ */
+ private class MapGet extends MapOrSetFlowStep, DataFlow::MethodCallNode {
+ MapGet() { this.getMethodName() = "get" }
+
+ override predicate load(DataFlow::Node obj, DataFlow::Node element, string prop) {
+ obj = this.getReceiver() and
+ element = this and
+ prop = mapValue(this.getArgument(0))
+ }
+
+ override predicate canLoadKnownKey() { any() }
+ }
+
+ /**
+ * A call to the `set` method on a Map.
+ *
+ * If the key of the call to `set` has a known string value,
+ * then the value will be saved into a pseudo-property corresponding to the known string value.
+ * The value will additionally be saved into a pseudo-property corresponding to values with unknown keys.
+ */
+ private class MapSet extends MapOrSetFlowStep, DataFlow::MethodCallNode {
+ MapSet() { this.getMethodName() = "set" }
+
+ override predicate store(DataFlow::Node element, DataFlow::Node obj, string prop) {
+ obj = this.getReceiver().getALocalSource() and
+ element = this.getArgument(1) and
+ // Makes sure that both known and unknown gets will work.
+ prop = [mapValue(this.getArgument(0)), mapValueUnknownKey()]
+ }
+ }
+
+ /**
+ * A step for a call to `values` on a Map or a Set.
+ */
+ private class MapAndSetValues extends MapOrSetFlowStep, DataFlow::MethodCallNode {
+ MapAndSetValues() { this.getMethodName() = "values" }
+
+ override predicate loadStore(
+ DataFlow::Node pred, DataFlow::Node succ, string fromProp, string toProp
+ ) {
+ pred = this.getReceiver() and
+ succ = this and
+ fromProp = [mapValueUnknownKey(),setElement()] and
+ toProp = iteratorElement()
+ }
+ }
+
+ /**
+ * A step for a call to `keys` on a Set.
+ */
+ private class SetKeys extends MapOrSetFlowStep, DataFlow::MethodCallNode {
+ SetKeys() { this.getMethodName() = "keys" }
+
+ override predicate loadStore(
+ DataFlow::Node pred, DataFlow::Node succ, string fromProp, string toProp
+ ) {
+ pred = this.getReceiver() and
+ succ = this and
+ fromProp = setElement() and
+ toProp = iteratorElement()
+ }
+ }
+}
diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll
index 35fbac21d36..bd369b2b0a9 100644
--- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll
+++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll
@@ -579,15 +579,50 @@ abstract class AdditionalFlowStep extends DataFlow::Node {
* For use with load/store steps in `DataFlow::AdditionalFlowStep` and TypeTracking.
*/
module PseudoProperties {
+ /**
+ * Gets a pseudo-property representing elements inside a `Set`
+ */
+ string setElement() { result = "$setElement$" }
+
+ /**
+ * Gets a pseudo-property representing elements inside a JavaScript iterator.
+ */
+ string iteratorElement() { result = "$iteratorElement$" }
+
/**
* Gets a pseudo-field representing an elements inside an `Array`.
*/
string arrayElement() { result = "$arrayElement$" }
/**
- * Gets a pseudo-property representing elements inside some array-like object.
+ * Gets a pseudo-property representing elements inside some array-like object. (Set, Array, or Iterator).
*/
- string arrayLikeElement() { result = arrayElement() }
+ string arrayLikeElement() { result = [setElement(), iteratorElement(), arrayElement()] }
+
+ /**
+ * Gets a pseudo-property representing the values of a Map, where the key is unknown.
+ */
+ string mapValueUnknownKey() { result = "$UnknownMapValue$" }
+
+ /**
+ * Gets a pseudo property for a Map value where the key is `key`.
+ * The string value of the `key` is encoded in the result, and there is only a result if the string value of `key` is known.
+ */
+ pragma[inline]
+ string mapValueKnownKey(DataFlow::Node key) {
+ exists(string s | key.mayHaveStringValue(s) | result = "$mapValue|" + s + "$")
+ }
+
+ /**
+ * Gets a psuedo property for a map value where the key is `key`.
+ */
+ pragma[inline]
+ string mapValue(DataFlow::Node key) {
+ result = mapValueKnownKey(key)
+ or
+ not exists(mapValueKnownKey(key)) and
+ result = mapValueUnknownKey()
+ }
}
/**
diff --git a/javascript/ql/test/library-tests/frameworks/Sets/test.expected b/javascript/ql/test/library-tests/frameworks/Sets/test.expected
new file mode 100644
index 00000000000..6add9605a8d
--- /dev/null
+++ b/javascript/ql/test/library-tests/frameworks/Sets/test.expected
@@ -0,0 +1,26 @@
+dataFlow
+| tst.js:2:16:2:23 | source() | tst.js:7:7:7:7 | e |
+| tst.js:2:16:2:23 | source() | tst.js:11:10:11:10 | e |
+| tst.js:2:16:2:23 | source() | tst.js:17:10:17:10 | v |
+| tst.js:2:16:2:23 | source() | tst.js:21:10:21:14 | value |
+| tst.js:2:16:2:23 | source() | tst.js:26:10:26:14 | value |
+| tst.js:2:16:2:23 | source() | tst.js:30:7:30:7 | e |
+| tst.js:2:16:2:23 | source() | tst.js:34:7:34:7 | e |
+| tst.js:2:16:2:23 | source() | tst.js:38:7:38:7 | e |
+| tst.js:2:16:2:23 | source() | tst.js:42:7:42:7 | e |
+| tst.js:2:16:2:23 | source() | tst.js:46:7:46:7 | e |
+| tst.js:2:16:2:23 | source() | tst.js:50:10:50:10 | e |
+| tst.js:2:16:2:23 | source() | tst.js:53:8:53:21 | map.get("key") |
+| tst.js:2:16:2:23 | source() | tst.js:55:8:55:28 | map.get ... nKey()) |
+typeTracking
+| tst.js:2:16:2:23 | source() | tst.js:2:16:2:23 | source() |
+| tst.js:2:16:2:23 | source() | tst.js:6:14:6:14 | e |
+| tst.js:2:16:2:23 | source() | tst.js:10:15:10:15 | e |
+| tst.js:2:16:2:23 | source() | tst.js:16:15:16:15 | v |
+| tst.js:2:16:2:23 | source() | tst.js:20:20:20:24 | value |
+| tst.js:2:16:2:23 | source() | tst.js:25:14:25:18 | value |
+| tst.js:2:16:2:23 | source() | tst.js:29:14:29:14 | e |
+| tst.js:2:16:2:23 | source() | tst.js:33:14:33:14 | e |
+| tst.js:2:16:2:23 | source() | tst.js:37:14:37:14 | e |
+| tst.js:2:16:2:23 | source() | tst.js:45:14:45:14 | e |
+| tst.js:2:16:2:23 | source() | tst.js:53:8:53:21 | map.get("key") |
diff --git a/javascript/ql/test/library-tests/frameworks/Sets/test.ql b/javascript/ql/test/library-tests/frameworks/Sets/test.ql
new file mode 100644
index 00000000000..e2e274e7e08
--- /dev/null
+++ b/javascript/ql/test/library-tests/frameworks/Sets/test.ql
@@ -0,0 +1,32 @@
+import javascript
+private import semmle.javascript.dataflow.internal.StepSummary
+
+class Config extends DataFlow::Configuration {
+ Config() { this = "Config" }
+
+ override predicate isSource(DataFlow::Node source) { source.(DataFlow::CallNode).getCalleeName() = "source" }
+
+ override predicate isSink(DataFlow::Node sink) {
+ exists(DataFlow::CallNode call | call.getCalleeName() = "sink" | call.getAnArgument() = sink)
+ }
+}
+
+query predicate dataFlow(DataFlow::Node pred, DataFlow::Node succ) {
+ any(Config c).hasFlow(pred, succ)
+}
+
+DataFlow::SourceNode trackSource(DataFlow::TypeTracker t, DataFlow::SourceNode start) {
+ t.start() and
+ result.(DataFlow::CallNode).getCalleeName() = "source" and
+ start = result
+ or
+ exists(DataFlow::TypeTracker t2 | t = t2.step(trackSource(t2, start), result))
+ or
+ exists(DataFlow::TypeTracker t2 |
+ result = MapsAndSetsTypeTracking::mapOrSetStep(trackSource(t2, start), t, t2)
+ )
+}
+
+query DataFlow::SourceNode typeTracking(DataFlow::Node start) {
+ result = trackSource(DataFlow::TypeTracker::end(), start)
+}
diff --git a/javascript/ql/test/library-tests/frameworks/Sets/tst.js b/javascript/ql/test/library-tests/frameworks/Sets/tst.js
new file mode 100644
index 00000000000..1a8fd2cbc07
--- /dev/null
+++ b/javascript/ql/test/library-tests/frameworks/Sets/tst.js
@@ -0,0 +1,56 @@
+(function() {
+ var source = source();
+ var set = new Set();
+ set.add(source);
+
+ for (const e of set) {
+ sink(e); // NOT OK.
+ }
+
+ set.forEach(e => {
+ sink(e);
+ })
+
+ var map = new Map();
+ map.set("key", source); map.set(unknownKey(), source);
+ map.forEach(v => {
+ sink(v);
+ });
+
+ for (const [key, value] of map) {
+ sink(value); // NOT OK.
+ sink(key); // OK
+ }
+
+ for (const value of map.values()) {
+ sink(value); // NOT OK.
+ }
+
+ for (const e of set.values()) {
+ sink(e); // NOT OK
+ }
+
+ for (const e of set.keys()) {
+ sink(e); // NOT OK
+ }
+
+ for (const e of new Set(set.keys())) {
+ sink(e); // NOT OK
+ }
+
+ for (const e of new Set([source])) {
+ sink(e); // NOT OK (not caught by type-tracking, as it doesn't include array steps).
+ }
+
+ for (const e of new Set(set)) {
+ sink(e); // NOT OK
+ }
+
+ for (const e of Array.from(set)) {
+ sink(e); // NOT OK (not caught by type-tracking, as it doesn't include array steps).
+ }
+
+ sink(map.get("key")); // NOT OK.
+ sink(map.get("nonExistingKey")); // OK.
+ sink(map.get(unknownKey())); // NOT OK (for data-flow). OK for type-tracking.
+})();
From 8ae55fb1c4a5ac78795d99766b6459b3bd5cc9ce Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Tue, 31 Mar 2020 13:55:34 +0200
Subject: [PATCH 0026/1298] add top level QLDoc to MapAndSet.qll
---
.../ql/src/semmle/javascript/MapAndSet.qll | 32 +++++++++++--------
1 file changed, 19 insertions(+), 13 deletions(-)
diff --git a/javascript/ql/src/semmle/javascript/MapAndSet.qll b/javascript/ql/src/semmle/javascript/MapAndSet.qll
index aed3fe377a4..1a34c7d1a0e 100644
--- a/javascript/ql/src/semmle/javascript/MapAndSet.qll
+++ b/javascript/ql/src/semmle/javascript/MapAndSet.qll
@@ -1,3 +1,9 @@
+/**
+ * Provides predicates and classes for working with the standard library implementations of
+ * [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) and
+ * [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set)
+ */
+
import javascript
private import semmle.javascript.dataflow.internal.StepSummary
private import DataFlow::PseudoProperties
@@ -83,7 +89,7 @@ module MapsAndSetsTypeTracking {
exists(MapOrSetFlowStep step, string field |
summary = LoadStep(field) and
step.load(pred, result, field) and
- (not step.canLoadKnownKey() or not field = mapValueUnknownKey()) // for a step that could load a known key, we prune the steps where the key is unknown.
+ (not step.canLoadKnownKey() or not field = mapValueUnknownKey()) // for a step that could load a known key, we prune the steps where the key is unknown.
or
summary = StoreStep(field) and
step.store(pred, result, field)
@@ -118,7 +124,7 @@ module MapsAndSetsTypeTracking {
any(MapOrSetFlowStep step).store(_, _, this)
}
- override string getLoadStoreToProp() {
+ override string getLoadStoreToProp() {
exists(MapOrSetFlowStep step | step.loadStore(_, _, this, result))
}
}
@@ -163,9 +169,9 @@ private module MapAndSetDataFlow {
* A step for a `for of` statement on a Map, Set, or Iterator.
* For Sets and iterators the l-value are the elements of the set/iterator.
* For Maps the l-value is a tuple containing a key and a value.
- *
- * This is partially duplicated behavior with the `for of` step for Arrays (in Arrays.qll).
- * This duplication is required for the type-tracking steps defined in `MapsAndSetsTypeTracking`.
+ *
+ * This is partially duplicated behavior with the `for of` step for Arrays (in Arrays.qll).
+ * This duplication is required for the type-tracking steps defined in `MapsAndSetsTypeTracking`.
*/
private class ForOfStep extends MapOrSetFlowStep, DataFlow::ValueNode {
ForOfStmt forOf;
@@ -223,9 +229,9 @@ private module MapAndSetDataFlow {
/**
* A call to the `set` method on a Map.
- *
- * If the key of the call to `set` has a known string value,
- * then the value will be saved into a pseudo-property corresponding to the known string value.
+ *
+ * If the key of the call to `set` has a known string value,
+ * then the value will be saved into a pseudo-property corresponding to the known string value.
* The value will additionally be saved into a pseudo-property corresponding to values with unknown keys.
*/
private class MapSet extends MapOrSetFlowStep, DataFlow::MethodCallNode {
@@ -239,9 +245,9 @@ private module MapAndSetDataFlow {
}
}
- /**
+ /**
* A step for a call to `values` on a Map or a Set.
- */
+ */
private class MapAndSetValues extends MapOrSetFlowStep, DataFlow::MethodCallNode {
MapAndSetValues() { this.getMethodName() = "values" }
@@ -250,14 +256,14 @@ private module MapAndSetDataFlow {
) {
pred = this.getReceiver() and
succ = this and
- fromProp = [mapValueUnknownKey(),setElement()] and
+ fromProp = [mapValueUnknownKey(), setElement()] and
toProp = iteratorElement()
}
}
- /**
+ /**
* A step for a call to `keys` on a Set.
- */
+ */
private class SetKeys extends MapOrSetFlowStep, DataFlow::MethodCallNode {
SetKeys() { this.getMethodName() = "keys" }
From 64c813612f5715c20e7fa9f039588e22ac5b3751 Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Tue, 31 Mar 2020 13:56:01 +0200
Subject: [PATCH 0027/1298] autoformat
---
.../javascript/dataflow/internal/StepSummary.qll | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll
index 67c51ff975c..4cef19c3c30 100644
--- a/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll
+++ b/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll
@@ -26,8 +26,8 @@ abstract class TypeTrackingPseudoProperty extends string {
TypeTrackingPseudoProperty() { any() }
/**
- * Gets a property name that `this` can be copied to in a `LoadStoreStep(this, result)`.
- */
+ * Gets a property name that `this` can be copied to in a `LoadStoreStep(this, result)`.
+ */
string getLoadStoreToProp() { none() }
}
@@ -41,10 +41,9 @@ newtype TStepSummary =
StoreStep(PropertyName prop) or
LoadStep(PropertyName prop) or
LoadStoreStep(PropertyName fromProp, PropertyName toProp) {
- fromProp = toProp or
- exists(TypeTrackingPseudoProperty prop |
- fromProp = prop and toProp = prop.getLoadStoreToProp()
- )
+ fromProp = toProp
+ or
+ exists(TypeTrackingPseudoProperty prop | fromProp = prop and toProp = prop.getLoadStoreToProp())
}
/**
From cec2cd3b1458d0a4001a31008e5f83d35a405ef9 Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Tue, 31 Mar 2020 14:05:01 +0200
Subject: [PATCH 0028/1298] update expected output
---
.../library-tests/Promises/tests.expected | 136 +++++++++---------
1 file changed, 68 insertions(+), 68 deletions(-)
diff --git a/javascript/ql/test/library-tests/Promises/tests.expected b/javascript/ql/test/library-tests/Promises/tests.expected
index 44dfa0d22e2..fecf4726989 100644
--- a/javascript/ql/test/library-tests/Promises/tests.expected
+++ b/javascript/ql/test/library-tests/Promises/tests.expected
@@ -222,135 +222,135 @@ flow
exclusiveTaintFlow
| interflow.js:3:18:3:25 | "source" | interflow.js:18:10:18:14 | error |
typetrack
-| flow.js:20:2:20:43 | Promise ... ink(x)) | flow.js:20:36:20:42 | sink(x) | in $PromiseResolveField$ |
+| flow.js:20:2:20:43 | Promise ... ink(x)) | flow.js:20:36:20:42 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:20:2:20:43 | Promise ... ink(x)) | flow.js:20:36:20:42 | sink(x) | store $PromiseResolveField$ |
| flow.js:20:31:20:31 | x | flow.js:20:2:20:24 | Promise ... source) | load $PromiseResolveField$ |
-| flow.js:22:2:22:56 | Promise ... ink(y)) | flow.js:22:36:22:41 | foo(x) | in $PromiseResolveField$ |
+| flow.js:22:2:22:56 | Promise ... ink(y)) | flow.js:22:36:22:41 | foo(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:22:2:22:56 | Promise ... ink(y)) | flow.js:22:36:22:41 | foo(x) | store $PromiseResolveField$ |
-| flow.js:22:2:22:56 | Promise ... ink(y)) | flow.js:22:49:22:55 | sink(y) | in $PromiseResolveField$ |
+| flow.js:22:2:22:56 | Promise ... ink(y)) | flow.js:22:49:22:55 | sink(y) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:22:2:22:56 | Promise ... ink(y)) | flow.js:22:49:22:55 | sink(y) | store $PromiseResolveField$ |
| flow.js:22:31:22:31 | x | flow.js:22:2:22:24 | Promise ... source) | load $PromiseResolveField$ |
-| flow.js:24:2:24:68 | new Pro ... ink(x)) | flow.js:24:61:24:67 | sink(x) | in $PromiseResolveField$ |
+| flow.js:24:2:24:68 | new Pro ... ink(x)) | flow.js:24:61:24:67 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:24:2:24:68 | new Pro ... ink(x)) | flow.js:24:61:24:67 | sink(x) | store $PromiseResolveField$ |
| flow.js:24:56:24:56 | x | flow.js:24:2:24:49 | new Pro ... ource)) | load $PromiseResolveField$ |
-| flow.js:26:2:26:81 | new Pro ... ink(y)) | flow.js:26:61:26:66 | foo(x) | in $PromiseResolveField$ |
+| flow.js:26:2:26:81 | new Pro ... ink(y)) | flow.js:26:61:26:66 | foo(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:26:2:26:81 | new Pro ... ink(y)) | flow.js:26:61:26:66 | foo(x) | store $PromiseResolveField$ |
-| flow.js:26:2:26:81 | new Pro ... ink(y)) | flow.js:26:74:26:80 | sink(y) | in $PromiseResolveField$ |
+| flow.js:26:2:26:81 | new Pro ... ink(y)) | flow.js:26:74:26:80 | sink(y) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:26:2:26:81 | new Pro ... ink(y)) | flow.js:26:74:26:80 | sink(y) | store $PromiseResolveField$ |
| flow.js:26:56:26:56 | x | flow.js:26:2:26:49 | new Pro ... ource)) | load $PromiseResolveField$ |
-| flow.js:28:2:28:60 | Promise ... ink(z)) | flow.js:28:53:28:59 | sink(z) | in $PromiseResolveField$ |
+| flow.js:28:2:28:60 | Promise ... ink(z)) | flow.js:28:53:28:59 | sink(z) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:28:2:28:60 | Promise ... ink(z)) | flow.js:28:53:28:59 | sink(z) | store $PromiseResolveField$ |
| flow.js:28:30:28:30 | x | flow.js:28:2:28:23 | Promise ... ("foo") | load $PromiseResolveField$ |
| flow.js:28:48:28:48 | z | flow.js:28:2:28:41 | Promise ... source) | load $PromiseResolveField$ |
-| flow.js:30:2:30:60 | Promise ... ink(z)) | flow.js:30:53:30:59 | sink(z) | in $PromiseResolveField$ |
+| flow.js:30:2:30:60 | Promise ... ink(z)) | flow.js:30:53:30:59 | sink(z) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:30:2:30:60 | Promise ... ink(z)) | flow.js:30:53:30:59 | sink(z) | store $PromiseResolveField$ |
| flow.js:30:31:30:31 | x | flow.js:30:2:30:24 | Promise ... source) | load $PromiseResolveField$ |
| flow.js:30:48:30:48 | z | flow.js:30:2:30:41 | Promise ... "foo") | load $PromiseResolveField$ |
-| flow.js:32:2:32:69 | new Pro ... ink(x)) | flow.js:32:2:32:49 | new Pro ... ource)) | in $PromiseResolveField$ |
-| flow.js:32:2:32:69 | new Pro ... ink(x)) | flow.js:32:62:32:68 | sink(x) | in $PromiseResolveField$ |
+| flow.js:32:2:32:69 | new Pro ... ink(x)) | flow.js:32:2:32:49 | new Pro ... ource)) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:32:2:32:69 | new Pro ... ink(x)) | flow.js:32:62:32:68 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:32:2:32:69 | new Pro ... ink(x)) | flow.js:32:62:32:68 | sink(x) | store $PromiseResolveField$ |
-| flow.js:34:2:34:41 | Promise ... => { }) | flow.js:34:2:34:24 | Promise ... source) | in $PromiseResolveField$ |
-| flow.js:34:2:34:60 | Promise ... ink(a)) | flow.js:34:53:34:59 | sink(a) | in $PromiseResolveField$ |
+| flow.js:34:2:34:41 | Promise ... => { }) | flow.js:34:2:34:24 | Promise ... source) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:34:2:34:60 | Promise ... ink(a)) | flow.js:34:53:34:59 | sink(a) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:34:2:34:60 | Promise ... ink(a)) | flow.js:34:53:34:59 | sink(a) | store $PromiseResolveField$ |
| flow.js:34:48:34:48 | a | flow.js:34:2:34:41 | Promise ... => { }) | load $PromiseResolveField$ |
-| flow.js:37:11:37:29 | p5.catch(() => { }) | flow.js:36:11:36:33 | Promise ... source) | in $PromiseResolveField$ |
-| flow.js:38:11:38:31 | p6.then ... ink(a)) | flow.js:38:24:38:30 | sink(a) | in $PromiseResolveField$ |
+| flow.js:37:11:37:29 | p5.catch(() => { }) | flow.js:36:11:36:33 | Promise ... source) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:38:11:38:31 | p6.then ... ink(a)) | flow.js:38:24:38:30 | sink(a) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:38:11:38:31 | p6.then ... ink(a)) | flow.js:38:24:38:30 | sink(a) | store $PromiseResolveField$ |
-| flow.js:40:2:40:85 | new Pro ... ink(x)) | flow.js:40:2:40:65 | new Pro ... => { }) | in $PromiseResolveField$ |
-| flow.js:40:2:40:85 | new Pro ... ink(x)) | flow.js:40:78:40:84 | sink(x) | in $PromiseResolveField$ |
+| flow.js:40:2:40:85 | new Pro ... ink(x)) | flow.js:40:2:40:65 | new Pro ... => { }) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:40:2:40:85 | new Pro ... ink(x)) | flow.js:40:78:40:84 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:40:2:40:85 | new Pro ... ink(x)) | flow.js:40:78:40:84 | sink(x) | store $PromiseResolveField$ |
-| flow.js:42:2:42:96 | new Pro ... ink(x)) | flow.js:42:2:42:76 | new Pro ... => { }) | in $PromiseResolveField$ |
-| flow.js:42:2:42:96 | new Pro ... ink(x)) | flow.js:42:89:42:95 | sink(x) | in $PromiseResolveField$ |
+| flow.js:42:2:42:96 | new Pro ... ink(x)) | flow.js:42:2:42:76 | new Pro ... => { }) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:42:2:42:96 | new Pro ... ink(x)) | flow.js:42:89:42:95 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:42:2:42:96 | new Pro ... ink(x)) | flow.js:42:89:42:95 | sink(x) | store $PromiseResolveField$ |
-| flow.js:44:2:44:41 | Promise ... => { }) | flow.js:44:2:44:24 | Promise ... source) | in $PromiseResolveField$ |
-| flow.js:44:2:44:58 | Promise ... => { }) | flow.js:44:2:44:41 | Promise ... => { }) | in $PromiseResolveField$ |
-| flow.js:44:2:44:75 | Promise ... => { }) | flow.js:44:2:44:58 | Promise ... => { }) | in $PromiseResolveField$ |
-| flow.js:44:2:44:94 | Promise ... ink(a)) | flow.js:44:87:44:93 | sink(a) | in $PromiseResolveField$ |
+| flow.js:44:2:44:41 | Promise ... => { }) | flow.js:44:2:44:24 | Promise ... source) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:44:2:44:58 | Promise ... => { }) | flow.js:44:2:44:41 | Promise ... => { }) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:44:2:44:75 | Promise ... => { }) | flow.js:44:2:44:58 | Promise ... => { }) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:44:2:44:94 | Promise ... ink(a)) | flow.js:44:87:44:93 | sink(a) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:44:2:44:94 | Promise ... ink(a)) | flow.js:44:87:44:93 | sink(a) | store $PromiseResolveField$ |
| flow.js:44:82:44:82 | a | flow.js:44:2:44:75 | Promise ... => { }) | load $PromiseResolveField$ |
-| flow.js:46:2:46:43 | Promise ... => { }) | flow.js:46:2:46:24 | Promise ... source) | in $PromiseResolveField$ |
-| flow.js:46:2:46:62 | Promise ... ink(a)) | flow.js:46:55:46:61 | sink(a) | in $PromiseResolveField$ |
+| flow.js:46:2:46:43 | Promise ... => { }) | flow.js:46:2:46:24 | Promise ... source) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:46:2:46:62 | Promise ... ink(a)) | flow.js:46:55:46:61 | sink(a) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:46:2:46:62 | Promise ... ink(a)) | flow.js:46:55:46:61 | sink(a) | store $PromiseResolveField$ |
| flow.js:46:50:46:50 | a | flow.js:46:2:46:43 | Promise ... => { }) | load $PromiseResolveField$ |
-| flow.js:48:2:48:56 | new Pro ... ink(x)) | flow.js:48:2:48:36 | new Pro ... urce }) | in $PromiseResolveField$ |
-| flow.js:48:2:48:56 | new Pro ... ink(x)) | flow.js:48:49:48:55 | sink(x) | in $PromiseResolveField$ |
+| flow.js:48:2:48:56 | new Pro ... ink(x)) | flow.js:48:2:48:36 | new Pro ... urce }) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:48:2:48:56 | new Pro ... ink(x)) | flow.js:48:49:48:55 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:48:2:48:56 | new Pro ... ink(x)) | flow.js:48:49:48:55 | sink(x) | store $PromiseResolveField$ |
-| flow.js:53:2:53:41 | createP ... ink(v)) | flow.js:53:34:53:40 | sink(v) | in $PromiseResolveField$ |
+| flow.js:53:2:53:41 | createP ... ink(v)) | flow.js:53:34:53:40 | sink(v) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:53:2:53:41 | createP ... ink(v)) | flow.js:53:34:53:40 | sink(v) | store $PromiseResolveField$ |
| flow.js:53:29:53:29 | v | flow.js:53:2:53:22 | createP ... source) | load $PromiseResolveField$ |
-| flow.js:58:2:58:26 | p10.cat ... ink(x)) | flow.js:57:12:57:31 | p9.finally(() => {}) | in $PromiseResolveField$ |
-| flow.js:58:2:58:26 | p10.cat ... ink(x)) | flow.js:58:19:58:25 | sink(x) | in $PromiseResolveField$ |
+| flow.js:58:2:58:26 | p10.cat ... ink(x)) | flow.js:57:12:57:31 | p9.finally(() => {}) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:58:2:58:26 | p10.cat ... ink(x)) | flow.js:58:19:58:25 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:58:2:58:26 | p10.cat ... ink(x)) | flow.js:58:19:58:25 | sink(x) | store $PromiseResolveField$ |
-| flow.js:62:2:62:24 | p12.cat ... ink(x)) | flow.js:61:12:61:29 | p11.then(() => {}) | in $PromiseResolveField$ |
-| flow.js:62:2:62:24 | p12.cat ... ink(x)) | flow.js:62:17:62:23 | sink(x) | in $PromiseResolveField$ |
+| flow.js:62:2:62:24 | p12.cat ... ink(x)) | flow.js:61:12:61:29 | p11.then(() => {}) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:62:2:62:24 | p12.cat ... ink(x)) | flow.js:62:17:62:23 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:62:2:62:24 | p12.cat ... ink(x)) | flow.js:62:17:62:23 | sink(x) | store $PromiseResolveField$ |
| flow.js:65:3:65:56 | await n ... ource)) | flow.js:65:9:65:56 | new Pro ... ource)) | load $PromiseResolveField$ |
-| flow.js:76:2:76:52 | chained ... ink(e)) | flow.js:76:2:76:32 | chained ... => {}) | in $PromiseResolveField$ |
-| flow.js:76:2:76:52 | chained ... ink(e)) | flow.js:76:45:76:51 | sink(e) | in $PromiseResolveField$ |
+| flow.js:76:2:76:52 | chained ... ink(e)) | flow.js:76:2:76:32 | chained ... => {}) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:76:2:76:52 | chained ... ink(e)) | flow.js:76:45:76:51 | sink(e) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:76:2:76:52 | chained ... ink(e)) | flow.js:76:45:76:51 | sink(e) | store $PromiseResolveField$ |
-| flow.js:79:3:79:22 | p.then(x => sink(x)) | flow.js:79:15:79:21 | sink(x) | in $PromiseResolveField$ |
+| flow.js:79:3:79:22 | p.then(x => sink(x)) | flow.js:79:15:79:21 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:79:3:79:22 | p.then(x => sink(x)) | flow.js:79:15:79:21 | sink(x) | store $PromiseResolveField$ |
-| flow.js:84:3:84:23 | p.catch ... ink(e)) | flow.js:83:32:83:32 | p | in $PromiseResolveField$ |
-| flow.js:84:3:84:23 | p.catch ... ink(e)) | flow.js:84:16:84:22 | sink(e) | in $PromiseResolveField$ |
+| flow.js:84:3:84:23 | p.catch ... ink(e)) | flow.js:83:32:83:32 | p | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:84:3:84:23 | p.catch ... ink(e)) | flow.js:84:16:84:22 | sink(e) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:84:3:84:23 | p.catch ... ink(e)) | flow.js:84:16:84:22 | sink(e) | store $PromiseResolveField$ |
-| flow.js:89:3:89:47 | ("foo", ... ink(e)) | flow.js:89:3:89:27 | ("foo", ... => {}) | in $PromiseResolveField$ |
-| flow.js:89:3:89:47 | ("foo", ... ink(e)) | flow.js:89:40:89:46 | sink(e) | in $PromiseResolveField$ |
+| flow.js:89:3:89:47 | ("foo", ... ink(e)) | flow.js:89:3:89:27 | ("foo", ... => {}) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:89:3:89:47 | ("foo", ... ink(e)) | flow.js:89:40:89:46 | sink(e) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:89:3:89:47 | ("foo", ... ink(e)) | flow.js:89:40:89:46 | sink(e) | store $PromiseResolveField$ |
-| flow.js:103:2:103:76 | new Pro ... ource}) | flow.js:103:2:103:48 | new Pro ... "BLA")) | in $PromiseResolveField$ |
-| flow.js:103:2:103:95 | new Pro ... ink(x)) | flow.js:103:88:103:94 | sink(x) | in $PromiseResolveField$ |
+| flow.js:103:2:103:76 | new Pro ... ource}) | flow.js:103:2:103:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:103:2:103:95 | new Pro ... ink(x)) | flow.js:103:88:103:94 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:103:2:103:95 | new Pro ... ink(x)) | flow.js:103:88:103:94 | sink(x) | store $PromiseResolveField$ |
| flow.js:103:83:103:83 | x | flow.js:103:2:103:76 | new Pro ... ource}) | load $PromiseResolveField$ |
-| flow.js:105:2:105:77 | new Pro ... ource}) | flow.js:105:2:105:48 | new Pro ... "BLA")) | in $PromiseResolveField$ |
-| flow.js:105:2:105:97 | new Pro ... ink(x)) | flow.js:105:2:105:77 | new Pro ... ource}) | in $PromiseResolveField$ |
-| flow.js:105:2:105:97 | new Pro ... ink(x)) | flow.js:105:90:105:96 | sink(x) | in $PromiseResolveField$ |
+| flow.js:105:2:105:77 | new Pro ... ource}) | flow.js:105:2:105:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:105:2:105:97 | new Pro ... ink(x)) | flow.js:105:2:105:77 | new Pro ... ource}) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:105:2:105:97 | new Pro ... ink(x)) | flow.js:105:90:105:96 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:105:2:105:97 | new Pro ... ink(x)) | flow.js:105:90:105:96 | sink(x) | store $PromiseResolveField$ |
-| flow.js:109:2:109:71 | new Pro ... jected) | flow.js:109:2:109:48 | new Pro ... "BLA")) | in $PromiseResolveField$ |
-| flow.js:109:2:109:91 | new Pro ... ink(x)) | flow.js:109:2:109:71 | new Pro ... jected) | in $PromiseResolveField$ |
-| flow.js:109:2:109:91 | new Pro ... ink(x)) | flow.js:109:84:109:90 | sink(x) | in $PromiseResolveField$ |
+| flow.js:109:2:109:71 | new Pro ... jected) | flow.js:109:2:109:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:109:2:109:91 | new Pro ... ink(x)) | flow.js:109:2:109:71 | new Pro ... jected) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:109:2:109:91 | new Pro ... ink(x)) | flow.js:109:84:109:90 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:109:2:109:91 | new Pro ... ink(x)) | flow.js:109:84:109:90 | sink(x) | store $PromiseResolveField$ |
-| flow.js:111:2:111:69 | new Pro ... jected) | flow.js:111:2:111:48 | new Pro ... "BLA")) | in $PromiseResolveField$ |
-| flow.js:111:2:111:88 | new Pro ... ink(x)) | flow.js:111:81:111:87 | sink(x) | in $PromiseResolveField$ |
+| flow.js:111:2:111:69 | new Pro ... jected) | flow.js:111:2:111:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:111:2:111:88 | new Pro ... ink(x)) | flow.js:111:81:111:87 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:111:2:111:88 | new Pro ... ink(x)) | flow.js:111:81:111:87 | sink(x) | store $PromiseResolveField$ |
| flow.js:111:76:111:76 | x | flow.js:111:2:111:69 | new Pro ... jected) | load $PromiseResolveField$ |
-| flow.js:113:2:113:69 | new Pro ... jected) | flow.js:113:2:113:48 | new Pro ... "BLA")) | in $PromiseResolveField$ |
-| flow.js:113:2:113:89 | new Pro ... ink(x)) | flow.js:113:2:113:69 | new Pro ... jected) | in $PromiseResolveField$ |
-| flow.js:113:2:113:89 | new Pro ... ink(x)) | flow.js:113:82:113:88 | sink(x) | in $PromiseResolveField$ |
+| flow.js:113:2:113:69 | new Pro ... jected) | flow.js:113:2:113:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:113:2:113:89 | new Pro ... ink(x)) | flow.js:113:2:113:69 | new Pro ... jected) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:113:2:113:89 | new Pro ... ink(x)) | flow.js:113:82:113:88 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:113:2:113:89 | new Pro ... ink(x)) | flow.js:113:82:113:88 | sink(x) | store $PromiseResolveField$ |
-| flow.js:117:2:117:69 | new Pro ... solved) | flow.js:117:2:117:48 | new Pro ... "BLA")) | in $PromiseResolveField$ |
-| flow.js:117:2:117:89 | new Pro ... ink(x)) | flow.js:117:2:117:69 | new Pro ... solved) | in $PromiseResolveField$ |
-| flow.js:117:2:117:89 | new Pro ... ink(x)) | flow.js:117:82:117:88 | sink(x) | in $PromiseResolveField$ |
+| flow.js:117:2:117:69 | new Pro ... solved) | flow.js:117:2:117:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:117:2:117:89 | new Pro ... ink(x)) | flow.js:117:2:117:69 | new Pro ... solved) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:117:2:117:89 | new Pro ... ink(x)) | flow.js:117:82:117:88 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:117:2:117:89 | new Pro ... ink(x)) | flow.js:117:82:117:88 | sink(x) | store $PromiseResolveField$ |
-| flow.js:119:2:119:69 | new Pro ... solved) | flow.js:119:2:119:48 | new Pro ... "BLA")) | in $PromiseResolveField$ |
-| flow.js:119:2:119:88 | new Pro ... ink(x)) | flow.js:119:81:119:87 | sink(x) | in $PromiseResolveField$ |
+| flow.js:119:2:119:69 | new Pro ... solved) | flow.js:119:2:119:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:119:2:119:88 | new Pro ... ink(x)) | flow.js:119:81:119:87 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:119:2:119:88 | new Pro ... ink(x)) | flow.js:119:81:119:87 | sink(x) | store $PromiseResolveField$ |
| flow.js:119:76:119:76 | x | flow.js:119:2:119:69 | new Pro ... solved) | load $PromiseResolveField$ |
-| flow.js:121:2:121:61 | Promise ... ink(x)) | flow.js:121:2:121:41 | Promise ... solved) | in $PromiseResolveField$ |
-| flow.js:121:2:121:61 | Promise ... ink(x)) | flow.js:121:54:121:60 | sink(x) | in $PromiseResolveField$ |
+| flow.js:121:2:121:61 | Promise ... ink(x)) | flow.js:121:2:121:41 | Promise ... solved) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:121:2:121:61 | Promise ... ink(x)) | flow.js:121:54:121:60 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:121:2:121:61 | Promise ... ink(x)) | flow.js:121:54:121:60 | sink(x) | store $PromiseResolveField$ |
| flow.js:121:28:121:28 | x | flow.js:121:2:121:21 | Promise.resolve(123) | load $PromiseResolveField$ |
-| flow.js:123:2:123:60 | Promise ... ink(x)) | flow.js:123:53:123:59 | sink(x) | in $PromiseResolveField$ |
+| flow.js:123:2:123:60 | Promise ... ink(x)) | flow.js:123:53:123:59 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:123:2:123:60 | Promise ... ink(x)) | flow.js:123:53:123:59 | sink(x) | store $PromiseResolveField$ |
| flow.js:123:28:123:28 | x | flow.js:123:2:123:21 | Promise.resolve(123) | load $PromiseResolveField$ |
| flow.js:123:48:123:48 | x | flow.js:123:2:123:41 | Promise ... solved) | load $PromiseResolveField$ |
-| flow.js:125:2:125:61 | Promise ... ink(x)) | flow.js:125:2:125:41 | Promise ... jected) | in $PromiseResolveField$ |
-| flow.js:125:2:125:61 | Promise ... ink(x)) | flow.js:125:54:125:60 | sink(x) | in $PromiseResolveField$ |
+| flow.js:125:2:125:61 | Promise ... ink(x)) | flow.js:125:2:125:41 | Promise ... jected) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:125:2:125:61 | Promise ... ink(x)) | flow.js:125:54:125:60 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:125:2:125:61 | Promise ... ink(x)) | flow.js:125:54:125:60 | sink(x) | store $PromiseResolveField$ |
| flow.js:125:28:125:28 | x | flow.js:125:2:125:21 | Promise.resolve(123) | load $PromiseResolveField$ |
-| flow.js:127:2:127:60 | Promise ... ink(x)) | flow.js:127:53:127:59 | sink(x) | in $PromiseResolveField$ |
+| flow.js:127:2:127:60 | Promise ... ink(x)) | flow.js:127:53:127:59 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:127:2:127:60 | Promise ... ink(x)) | flow.js:127:53:127:59 | sink(x) | store $PromiseResolveField$ |
| flow.js:127:28:127:28 | x | flow.js:127:2:127:21 | Promise.resolve(123) | load $PromiseResolveField$ |
| flow.js:127:48:127:48 | x | flow.js:127:2:127:41 | Promise ... jected) | load $PromiseResolveField$ |
-| flow.js:129:2:129:71 | new Pro ... ink(x)) | flow.js:129:64:129:70 | sink(x) | in $PromiseResolveField$ |
+| flow.js:129:2:129:71 | new Pro ... ink(x)) | flow.js:129:64:129:70 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:129:2:129:71 | new Pro ... ink(x)) | flow.js:129:64:129:70 | sink(x) | store $PromiseResolveField$ |
| flow.js:129:59:129:59 | x | flow.js:129:2:129:52 | new Pro ... olved)) | load $PromiseResolveField$ |
-| flow.js:131:2:131:45 | Promise ... ink(x)) | flow.js:131:38:131:44 | sink(x) | in $PromiseResolveField$ |
+| flow.js:131:2:131:45 | Promise ... ink(x)) | flow.js:131:38:131:44 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
| flow.js:131:2:131:45 | Promise ... ink(x)) | flow.js:131:38:131:44 | sink(x) | store $PromiseResolveField$ |
| flow.js:131:33:131:33 | x | flow.js:131:2:131:26 | Promise ... solved) | load $PromiseResolveField$ |
-| interflow.js:6:3:9:23 | loadScr ... eError) | interflow.js:6:3:8:26 | loadScr ... () { }) | in $PromiseResolveField$ |
-| promises.js:23:3:25:4 | promise ... v;\\n }) | promises.js:10:18:17:4 | new Pro ... );\\n }) | in $PromiseResolveField$ |
-| promises.js:33:19:35:6 | new Pro ... \\n }) | promises.js:34:17:34:22 | source | in $PromiseResolveField$ |
+| interflow.js:6:3:9:23 | loadScr ... eError) | interflow.js:6:3:8:26 | loadScr ... () { }) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| promises.js:23:3:25:4 | promise ... v;\\n }) | promises.js:10:18:17:4 | new Pro ... );\\n }) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| promises.js:33:19:35:6 | new Pro ... \\n }) | promises.js:34:17:34:22 | source | copy $PromiseResolveField$ to $PromiseResolveField$ |
| promises.js:33:19:35:6 | new Pro ... \\n }) | promises.js:34:17:34:22 | source | store $PromiseResolveField$ |
-| promises.js:43:19:45:6 | Q.Promi ... \\n }) | promises.js:44:17:44:22 | source | in $PromiseResolveField$ |
+| promises.js:43:19:45:6 | Q.Promi ... \\n }) | promises.js:44:17:44:22 | source | copy $PromiseResolveField$ to $PromiseResolveField$ |
| promises.js:43:19:45:6 | Q.Promi ... \\n }) | promises.js:44:17:44:22 | source | store $PromiseResolveField$ |
| promises.js:71:34:71:36 | val | promises.js:71:5:71:27 | Promise ... source) | load $PromiseResolveField$ |
| promises.js:72:48:72:50 | val | promises.js:72:5:72:41 | new Pro ... ource)) | load $PromiseResolveField$ |
From 49a8a48a7254d5b6e3d6128c8895e55597518fe5 Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Tue, 31 Mar 2020 18:11:18 +0200
Subject: [PATCH 0029/1298] autoformat
---
javascript/ql/src/semmle/javascript/dataflow/Nodes.qll | 4 ++--
javascript/ql/test/library-tests/frameworks/Sets/test.ql | 4 +++-
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll
index 1a618db856e..89a454bb9c1 100644
--- a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll
+++ b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll
@@ -621,10 +621,10 @@ class ArrayCreationNode extends DataFlow::ValueNode, DataFlow::SourceNode {
result = this.(ArrayConstructorInvokeNode).getSize()
}
- /**
+ /**
* Gets a data flow node corresponding to an array of values being passed as
* individual arguments to this array creation.
- */
+ */
DataFlow::Node getASpreadArgument() {
exists(SpreadElement arg | arg = getAnElement().getEnclosingExpr() |
result = DataFlow::valueNode(arg.getOperand())
diff --git a/javascript/ql/test/library-tests/frameworks/Sets/test.ql b/javascript/ql/test/library-tests/frameworks/Sets/test.ql
index e2e274e7e08..3422b663239 100644
--- a/javascript/ql/test/library-tests/frameworks/Sets/test.ql
+++ b/javascript/ql/test/library-tests/frameworks/Sets/test.ql
@@ -4,7 +4,9 @@ private import semmle.javascript.dataflow.internal.StepSummary
class Config extends DataFlow::Configuration {
Config() { this = "Config" }
- override predicate isSource(DataFlow::Node source) { source.(DataFlow::CallNode).getCalleeName() = "source" }
+ override predicate isSource(DataFlow::Node source) {
+ source.(DataFlow::CallNode).getCalleeName() = "source"
+ }
override predicate isSink(DataFlow::Node sink) {
exists(DataFlow::CallNode call | call.getCalleeName() = "sink" | call.getAnArgument() = sink)
From 741317bd050326008c29ad076b736045c89a70ea Mon Sep 17 00:00:00 2001
From: Rebecca Valentine
Date: Tue, 31 Mar 2020 22:56:44 -0700
Subject: [PATCH 0030/1298] Python: ObjectAPI to ValueAPI: Makes isAbstract a
predicate in CallArgs
---
python/ql/src/Expressions/CallArgs.qll | 4 ++++
python/ql/src/Expressions/WrongNumberArgumentsInCall.ql | 2 +-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/python/ql/src/Expressions/CallArgs.qll b/python/ql/src/Expressions/CallArgs.qll
index 5dcf50ac8f4..b071bbac372 100644
--- a/python/ql/src/Expressions/CallArgs.qll
+++ b/python/ql/src/Expressions/CallArgs.qll
@@ -255,3 +255,7 @@ predicate overridden_call(FunctionValue func, FunctionValue overriding, Call cal
overriding.getACall().getNode() = call
}
+/** Holds if `func` will raise a `NotImplemented` error. */
+predicate isAbstract(FunctionValue func) {
+ func.getARaisedType() = ClassValue::notImplementedError()
+}
\ No newline at end of file
diff --git a/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql b/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql
index 4101bd3a854..02bc685c096 100644
--- a/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql
+++ b/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql
@@ -21,7 +21,7 @@ where
or
too_few_args(call, func, limit) and too = "too few arguments" and should = "no fewer than "
) and
-not func.isAbstract() and
+not isAbstract(func) and
not exists(FunctionValue overridden | func.overrides(overridden) and correct_args_if_called_as_method(call, overridden))
/* The semantics of `__new__` can be a bit subtle, so we simply exclude `__new__` methods */
and not func.getName() = "__new__"
From a188c6f80468c808780a3bd80ccbbdb7683781d0 Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Wed, 1 Apr 2020 11:12:54 +0200
Subject: [PATCH 0031/1298] qldoc changes and renaming
---
javascript/ql/src/javascript.qll | 2 +-
.../{MapAndSet.qll => Collections.qll} | 177 +++++++++---------
.../javascript/dataflow/Configuration.qll | 17 +-
.../{Sets => Collections}/test.expected | 0
.../frameworks/{Sets => Collections}/test.ql | 2 +-
.../frameworks/{Sets => Collections}/tst.js | 0
6 files changed, 96 insertions(+), 102 deletions(-)
rename javascript/ql/src/semmle/javascript/{MapAndSet.qll => Collections.qll} (55%)
rename javascript/ql/test/library-tests/frameworks/{Sets => Collections}/test.expected (100%)
rename javascript/ql/test/library-tests/frameworks/{Sets => Collections}/test.ql (92%)
rename javascript/ql/test/library-tests/frameworks/{Sets => Collections}/tst.js (100%)
diff --git a/javascript/ql/src/javascript.qll b/javascript/ql/src/javascript.qll
index 37a93dbf618..d00c63acdf6 100644
--- a/javascript/ql/src/javascript.qll
+++ b/javascript/ql/src/javascript.qll
@@ -12,6 +12,7 @@ import semmle.javascript.Base64
import semmle.javascript.CFG
import semmle.javascript.Classes
import semmle.javascript.Closure
+import semmle.javascript.Collections
import semmle.javascript.Comments
import semmle.javascript.Concepts
import semmle.javascript.Constants
@@ -36,7 +37,6 @@ import semmle.javascript.JsonParsers
import semmle.javascript.JSX
import semmle.javascript.Lines
import semmle.javascript.Locations
-import semmle.javascript.MapAndSet
import semmle.javascript.Modules
import semmle.javascript.NodeJS
import semmle.javascript.NPM
diff --git a/javascript/ql/src/semmle/javascript/MapAndSet.qll b/javascript/ql/src/semmle/javascript/Collections.qll
similarity index 55%
rename from javascript/ql/src/semmle/javascript/MapAndSet.qll
rename to javascript/ql/src/semmle/javascript/Collections.qll
index 1a34c7d1a0e..30b33114ccd 100644
--- a/javascript/ql/src/semmle/javascript/MapAndSet.qll
+++ b/javascript/ql/src/semmle/javascript/Collections.qll
@@ -1,7 +1,7 @@
/**
- * Provides predicates and classes for working with the standard library implementations of
- * [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) and
- * [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set)
+ * Provides predicates and classes for working with the standard library collection implementations.
+ * Currently [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) and
+ * [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) are implemented.
*/
import javascript
@@ -9,87 +9,80 @@ private import semmle.javascript.dataflow.internal.StepSummary
private import DataFlow::PseudoProperties
/**
- * Common predicates and classes for type and data-flow tracking on Maps and Sets.
+ * An `AdditionalFlowStep` used to model a data-flow step related to standard library collections.
+ *
+ * The `loadStep`/`storeStep`/`loadStoreStep` methods are overloaded such that the new predicates
+ * `load`/`store`/`loadStore` can be used in the `CollectionsTypeTracking` module.
+ * (Thereby avoiding naming conflicts with a "cousin" `AdditionalFlowStep` implementation.)
*/
-private module MapsAndSets {
- /**
- * An `AdditionalFlowStep` used to model a data-flow step related to Maps and Sets.
- *
- * The `loadStep`/`storeStep`/`loadStoreStep` methods are overloaded such that the new predicates
- * `load`/`store`/`loadStore` can be used in the `MapsAndSetsTypeTracking` module.
- * (Thereby avoiding conflicts with a "cousin" `AdditionalFlowStep` implementation.)
- */
- abstract class MapOrSetFlowStep extends DataFlow::AdditionalFlowStep {
- final override predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() }
+private abstract class CollectionFlowStep extends DataFlow::AdditionalFlowStep {
+ final override predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() }
- final override predicate step(
- DataFlow::Node p, DataFlow::Node s, DataFlow::FlowLabel pl, DataFlow::FlowLabel sl
- ) {
- none()
- }
-
- /**
- * Holds if the property `prop` of the object `pred` should be loaded into `succ`.
- */
- predicate load(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
-
- final override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
- this.load(pred, succ, prop)
- }
-
- /**
- * Holds if `pred` should be stored in the object `succ` under the property `prop`.
- */
- predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
-
- final override predicate storeStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
- this.store(pred, succ, prop)
- }
-
- /**
- * Holds if the property `prop` should be copied from the object `pred` to the object `succ`.
- */
- predicate loadStore(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
-
- final override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
- this.loadStore(pred, succ, prop, prop)
- }
-
- /**
- * Holds if the property `loadProp` should be copied from the object `pred` to the property `storeProp` of object `succ`.
- */
- predicate loadStore(DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp) {
- none()
- }
-
- final override predicate loadStoreStep(
- DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp
- ) {
- this.loadStore(pred, succ, loadProp, storeProp)
- }
-
- /**
- * Holds if this is a map step that could potentially load a value where the corresponding key has a known string value.
- */
- predicate canLoadKnownKey() { none() }
+ final override predicate step(
+ DataFlow::Node p, DataFlow::Node s, DataFlow::FlowLabel pl, DataFlow::FlowLabel sl
+ ) {
+ none()
}
+
+ /**
+ * Holds if the property `prop` of the object `pred` should be loaded into `succ`.
+ */
+ predicate load(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
+
+ final override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
+ this.load(pred, succ, prop)
+ }
+
+ /**
+ * Holds if `pred` should be stored in the object `succ` under the property `prop`.
+ */
+ predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
+
+ final override predicate storeStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
+ this.store(pred, succ, prop)
+ }
+
+ /**
+ * Holds if the property `prop` should be copied from the object `pred` to the object `succ`.
+ */
+ predicate loadStore(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
+
+ final override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
+ this.loadStore(pred, succ, prop, prop)
+ }
+
+ /**
+ * Holds if the property `loadProp` should be copied from the object `pred` to the property `storeProp` of object `succ`.
+ */
+ predicate loadStore(DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp) {
+ none()
+ }
+
+ final override predicate loadStoreStep(
+ DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp
+ ) {
+ this.loadStore(pred, succ, loadProp, storeProp)
+ }
+
+ /**
+ * Holds if this step on a collection can load a value with a known key.
+ */
+ predicate canLoadValueWithKnownKey() { none() }
}
/**
- * A collection of predicates and clases for type-tracking Maps and Sets.
+ * A collection of predicates and clases for type-tracking collections.
*/
-module MapsAndSetsTypeTracking {
- private import MapsAndSets
-
+module CollectionsTypeTracking {
/**
- * Gets the result from a single step through a Map or Set, from `pred` to `result` summarized by `summary`.
+ * Gets the result from a single step through a collection, from `pred` to `result` summarized by `summary`.
*/
pragma[inline]
- DataFlow::SourceNode mapOrSetStep(DataFlow::Node pred, StepSummary summary) {
- exists(MapOrSetFlowStep step, string field |
+ DataFlow::SourceNode collectionStep(DataFlow::Node pred, StepSummary summary) {
+ exists(CollectionFlowStep step, string field |
summary = LoadStep(field) and
step.load(pred, result, field) and
- (not step.canLoadKnownKey() or not field = mapValueUnknownKey()) // for a step that could load a known key, we prune the steps where the key is unknown.
+ (not step.canLoadValueWithKnownKey() or not field = mapValueUnknownKey()) // for a step that could load a known key, we prune the steps where the key is unknown.
or
summary = StoreStep(field) and
step.store(pred, result, field)
@@ -104,42 +97,40 @@ module MapsAndSetsTypeTracking {
}
/**
- * Gets the result from a single step through a Map or set, from `pred` with tracker `t2` to `result` with tracker `t`.
+ * Gets the result from a single step through a collection, from `pred` with tracker `t2` to `result` with tracker `t`.
*/
pragma[inline]
- DataFlow::SourceNode mapOrSetStep(
+ DataFlow::SourceNode collectionStep(
DataFlow::SourceNode pred, DataFlow::TypeTracker t, DataFlow::TypeTracker t2
) {
exists(DataFlow::Node mid, StepSummary summary | pred.flowsTo(mid) and t = t2.append(summary) |
- result = mapOrSetStep(mid, summary)
+ result = collectionStep(mid, summary)
)
}
/**
- * A class enabling the use of the Map and Set related pseudo-properties as a pseudo-property in type-tracking predicates.
+ * A class enabling the use of the collection related pseudo-properties in type-tracking predicates.
*/
private class MapRelatedPseudoFieldAsTypeTrackingProperty extends TypeTrackingPseudoProperty {
MapRelatedPseudoFieldAsTypeTrackingProperty() {
this = [setElement(), iteratorElement()] or
- any(MapOrSetFlowStep step).store(_, _, this)
+ any(CollectionFlowStep step).store(_, _, this)
}
override string getLoadStoreToProp() {
- exists(MapOrSetFlowStep step | step.loadStore(_, _, this, result))
+ exists(CollectionFlowStep step | step.loadStore(_, _, this, result))
}
}
}
/**
- * A module for data-flow steps related to `Set` and `Map`.
+ * A module for data-flow steps related standard library collection implementations.
*/
-private module MapAndSetDataFlow {
- private import MapsAndSets
-
+private module CollectionDataFlow {
/**
- * A step for an `add` method, which adds an element to a Set.
+ * A step for `Set.add()` method, which adds an element to a Set.
*/
- private class SetAdd extends MapOrSetFlowStep, DataFlow::MethodCallNode {
+ private class SetAdd extends CollectionFlowStep, DataFlow::MethodCallNode {
SetAdd() { this.getMethodName() = "add" }
override predicate store(DataFlow::Node element, DataFlow::Node obj, string prop) {
@@ -152,7 +143,7 @@ private module MapAndSetDataFlow {
/**
* A step for the `Set` constructor, which copies any elements from the first argument into the resulting set.
*/
- private class SetConstructor extends MapOrSetFlowStep, DataFlow::NewNode {
+ private class SetConstructor extends CollectionFlowStep, DataFlow::NewNode {
SetConstructor() { this = DataFlow::globalVarRef("Set").getAnInstantiation() }
override predicate loadStore(
@@ -171,9 +162,9 @@ private module MapAndSetDataFlow {
* For Maps the l-value is a tuple containing a key and a value.
*
* This is partially duplicated behavior with the `for of` step for Arrays (in Arrays.qll).
- * This duplication is required for the type-tracking steps defined in `MapsAndSetsTypeTracking`.
+ * This duplication is required for the type-tracking steps defined in `CollectionsTypeTracking`.
*/
- private class ForOfStep extends MapOrSetFlowStep, DataFlow::ValueNode {
+ private class ForOfStep extends CollectionFlowStep, DataFlow::ValueNode {
ForOfStmt forOf;
DataFlow::Node element;
@@ -201,7 +192,7 @@ private module MapAndSetDataFlow {
/**
* A step for a call to `forEach` on a Set or Map.
*/
- private class SetMapForEach extends MapOrSetFlowStep, DataFlow::MethodCallNode {
+ private class SetMapForEach extends CollectionFlowStep, DataFlow::MethodCallNode {
SetMapForEach() { this.getMethodName() = "forEach" }
override predicate load(DataFlow::Node obj, DataFlow::Node element, string prop) {
@@ -215,7 +206,7 @@ private module MapAndSetDataFlow {
* A call to the `get` method on a Map.
* If the key of the call to `get` has a known string value, then only the value corresponding to that key will be retrieved.
*/
- private class MapGet extends MapOrSetFlowStep, DataFlow::MethodCallNode {
+ private class MapGet extends CollectionFlowStep, DataFlow::MethodCallNode {
MapGet() { this.getMethodName() = "get" }
override predicate load(DataFlow::Node obj, DataFlow::Node element, string prop) {
@@ -224,7 +215,7 @@ private module MapAndSetDataFlow {
prop = mapValue(this.getArgument(0))
}
- override predicate canLoadKnownKey() { any() }
+ override predicate canLoadValueWithKnownKey() { any() }
}
/**
@@ -234,7 +225,7 @@ private module MapAndSetDataFlow {
* then the value will be saved into a pseudo-property corresponding to the known string value.
* The value will additionally be saved into a pseudo-property corresponding to values with unknown keys.
*/
- private class MapSet extends MapOrSetFlowStep, DataFlow::MethodCallNode {
+ private class MapSet extends CollectionFlowStep, DataFlow::MethodCallNode {
MapSet() { this.getMethodName() = "set" }
override predicate store(DataFlow::Node element, DataFlow::Node obj, string prop) {
@@ -248,7 +239,7 @@ private module MapAndSetDataFlow {
/**
* A step for a call to `values` on a Map or a Set.
*/
- private class MapAndSetValues extends MapOrSetFlowStep, DataFlow::MethodCallNode {
+ private class MapAndSetValues extends CollectionFlowStep, DataFlow::MethodCallNode {
MapAndSetValues() { this.getMethodName() = "values" }
override predicate loadStore(
@@ -264,7 +255,7 @@ private module MapAndSetDataFlow {
/**
* A step for a call to `keys` on a Set.
*/
- private class SetKeys extends MapOrSetFlowStep, DataFlow::MethodCallNode {
+ private class SetKeys extends CollectionFlowStep, DataFlow::MethodCallNode {
SetKeys() { this.getMethodName() = "keys" }
override predicate loadStore(
diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll
index bd369b2b0a9..01a77ab1b9a 100644
--- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll
+++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll
@@ -576,36 +576,39 @@ abstract class AdditionalFlowStep extends DataFlow::Node {
/**
* A collection of pseudo-properties that are used in multiple files.
+ *
+ * A pseudo-property represents the location where some value is stored in an object.
+ *
* For use with load/store steps in `DataFlow::AdditionalFlowStep` and TypeTracking.
*/
module PseudoProperties {
/**
- * Gets a pseudo-property representing elements inside a `Set`
+ * Gets a pseudo-property for the location of elements in a `Set`
*/
string setElement() { result = "$setElement$" }
/**
- * Gets a pseudo-property representing elements inside a JavaScript iterator.
+ * Gets a pseudo-property for the location of elements in a JavaScript iterator.
*/
string iteratorElement() { result = "$iteratorElement$" }
/**
- * Gets a pseudo-field representing an elements inside an `Array`.
+ * Gets a pseudo-property for the location of elements in an `Array`.
*/
string arrayElement() { result = "$arrayElement$" }
/**
- * Gets a pseudo-property representing elements inside some array-like object. (Set, Array, or Iterator).
+ * Gets a pseudo-property for the location of elements in some array-like object. (Set, Array, or Iterator).
*/
string arrayLikeElement() { result = [setElement(), iteratorElement(), arrayElement()] }
/**
- * Gets a pseudo-property representing the values of a Map, where the key is unknown.
+ * Gets a pseudo-property for the location of map values, where the key is unknown.
*/
string mapValueUnknownKey() { result = "$UnknownMapValue$" }
/**
- * Gets a pseudo property for a Map value where the key is `key`.
+ * Gets a pseudo-property for the location of a map value where the key is `key`.
* The string value of the `key` is encoded in the result, and there is only a result if the string value of `key` is known.
*/
pragma[inline]
@@ -614,7 +617,7 @@ module PseudoProperties {
}
/**
- * Gets a psuedo property for a map value where the key is `key`.
+ * Gets a pseudo-property for the location of a map value where the key is `key`.
*/
pragma[inline]
string mapValue(DataFlow::Node key) {
diff --git a/javascript/ql/test/library-tests/frameworks/Sets/test.expected b/javascript/ql/test/library-tests/frameworks/Collections/test.expected
similarity index 100%
rename from javascript/ql/test/library-tests/frameworks/Sets/test.expected
rename to javascript/ql/test/library-tests/frameworks/Collections/test.expected
diff --git a/javascript/ql/test/library-tests/frameworks/Sets/test.ql b/javascript/ql/test/library-tests/frameworks/Collections/test.ql
similarity index 92%
rename from javascript/ql/test/library-tests/frameworks/Sets/test.ql
rename to javascript/ql/test/library-tests/frameworks/Collections/test.ql
index 3422b663239..f03d02ea21b 100644
--- a/javascript/ql/test/library-tests/frameworks/Sets/test.ql
+++ b/javascript/ql/test/library-tests/frameworks/Collections/test.ql
@@ -25,7 +25,7 @@ DataFlow::SourceNode trackSource(DataFlow::TypeTracker t, DataFlow::SourceNode s
exists(DataFlow::TypeTracker t2 | t = t2.step(trackSource(t2, start), result))
or
exists(DataFlow::TypeTracker t2 |
- result = MapsAndSetsTypeTracking::mapOrSetStep(trackSource(t2, start), t, t2)
+ result = CollectionsTypeTracking::collectionStep(trackSource(t2, start), t, t2)
)
}
diff --git a/javascript/ql/test/library-tests/frameworks/Sets/tst.js b/javascript/ql/test/library-tests/frameworks/Collections/tst.js
similarity index 100%
rename from javascript/ql/test/library-tests/frameworks/Sets/tst.js
rename to javascript/ql/test/library-tests/frameworks/Collections/tst.js
From 9fc8ed17cdc1e22789a997d9a4c0935f3d44a9e1 Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Wed, 1 Apr 2020 11:18:11 +0200
Subject: [PATCH 0032/1298] remove unused import
---
javascript/ql/test/library-tests/frameworks/Collections/test.ql | 1 -
1 file changed, 1 deletion(-)
diff --git a/javascript/ql/test/library-tests/frameworks/Collections/test.ql b/javascript/ql/test/library-tests/frameworks/Collections/test.ql
index f03d02ea21b..61da4ade4ab 100644
--- a/javascript/ql/test/library-tests/frameworks/Collections/test.ql
+++ b/javascript/ql/test/library-tests/frameworks/Collections/test.ql
@@ -1,5 +1,4 @@
import javascript
-private import semmle.javascript.dataflow.internal.StepSummary
class Config extends DataFlow::Configuration {
Config() { this = "Config" }
From 1be326a37bd0a2965ea5ca9be13746f71b6e1985 Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Wed, 1 Apr 2020 11:21:05 +0200
Subject: [PATCH 0033/1298] add a CopyStep type-tracking step, for
loadStoreSteps that loads and stores the same property
---
javascript/ql/src/semmle/javascript/Collections.qll | 6 +++---
javascript/ql/src/semmle/javascript/Promises.qll | 2 +-
.../ql/src/semmle/javascript/dataflow/TypeTracking.qll | 4 ++++
.../src/semmle/javascript/dataflow/internal/StepSummary.qll | 5 +++--
4 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/javascript/ql/src/semmle/javascript/Collections.qll b/javascript/ql/src/semmle/javascript/Collections.qll
index 30b33114ccd..50c29d01de1 100644
--- a/javascript/ql/src/semmle/javascript/Collections.qll
+++ b/javascript/ql/src/semmle/javascript/Collections.qll
@@ -87,10 +87,10 @@ module CollectionsTypeTracking {
summary = StoreStep(field) and
step.store(pred, result, field)
or
+ summary = CopyStep(field) and
+ step.loadStore(pred, result, field)
+ or
exists(string toField | summary = LoadStoreStep(field, toField) |
- field = toField and
- step.loadStore(pred, result, field)
- or
step.loadStore(pred, result, field, toField)
)
)
diff --git a/javascript/ql/src/semmle/javascript/Promises.qll b/javascript/ql/src/semmle/javascript/Promises.qll
index 87a804dd113..ed7cf13e3b7 100644
--- a/javascript/ql/src/semmle/javascript/Promises.qll
+++ b/javascript/ql/src/semmle/javascript/Promises.qll
@@ -176,7 +176,7 @@ module PromiseTypeTracking {
summary = StoreStep(field) and
step.store(pred, result, field)
or
- summary = LoadStoreStep(field, field) and
+ summary = CopyStep(field) and
step.loadStore(pred, result, field)
)
}
diff --git a/javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll
index 57808e9c551..219e1fa652a 100644
--- a/javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll
+++ b/javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll
@@ -57,6 +57,8 @@ class TypeTracker extends TTypeTracker {
result = MkTypeTracker(hasCall, toProp)
)
or
+ step = CopyStep(prop) and result = this
+ or
step = CallStep() and result = MkTypeTracker(true, prop)
or
step = ReturnStep() and hasCall = false and result = this
@@ -219,6 +221,8 @@ class TypeBackTracker extends TTypeBackTracker {
result = MkTypeBackTracker(hasReturn, fromProp)
)
or
+ step = CopyStep(prop) and result = this
+ or
step = CallStep() and hasReturn = false and result = this
or
step = ReturnStep() and result = MkTypeBackTracker(true, prop)
diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll
index 4cef19c3c30..c4465285109 100644
--- a/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll
+++ b/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll
@@ -40,9 +40,8 @@ newtype TStepSummary =
ReturnStep() or
StoreStep(PropertyName prop) or
LoadStep(PropertyName prop) or
+ CopyStep(PropertyName prop) or
LoadStoreStep(PropertyName fromProp, PropertyName toProp) {
- fromProp = toProp
- or
exists(TypeTrackingPseudoProperty prop | fromProp = prop and toProp = prop.getLoadStoreToProp())
}
@@ -64,6 +63,8 @@ class StepSummary extends TStepSummary {
or
exists(string prop | this = LoadStep(prop) | result = "load " + prop)
or
+ exists(string prop | this = CopyStep(prop) | result = "copy " + prop)
+ or
exists(string fromProp, string toProp | this = LoadStoreStep(fromProp, toProp) |
result = "copy " + fromProp + " to " + toProp
)
From b2b009cdd9cf87a4fbc3f497337884b2162a80ed Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Wed, 1 Apr 2020 11:34:25 +0200
Subject: [PATCH 0034/1298] qldoc adjustment
---
javascript/ql/src/semmle/javascript/Collections.qll | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/javascript/ql/src/semmle/javascript/Collections.qll b/javascript/ql/src/semmle/javascript/Collections.qll
index 50c29d01de1..cdb60de6a6a 100644
--- a/javascript/ql/src/semmle/javascript/Collections.qll
+++ b/javascript/ql/src/semmle/javascript/Collections.qll
@@ -15,7 +15,7 @@ private import DataFlow::PseudoProperties
* `load`/`store`/`loadStore` can be used in the `CollectionsTypeTracking` module.
* (Thereby avoiding naming conflicts with a "cousin" `AdditionalFlowStep` implementation.)
*/
-private abstract class CollectionFlowStep extends DataFlow::AdditionalFlowStep {
+abstract private class CollectionFlowStep extends DataFlow::AdditionalFlowStep {
final override predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() }
final override predicate step(
@@ -82,7 +82,10 @@ module CollectionsTypeTracking {
exists(CollectionFlowStep step, string field |
summary = LoadStep(field) and
step.load(pred, result, field) and
- (not step.canLoadValueWithKnownKey() or not field = mapValueUnknownKey()) // for a step that could load a known key, we prune the steps where the key is unknown.
+ not (
+ step.canLoadValueWithKnownKey() and // for a step that could load a known key,
+ field = mapValueUnknownKey() // don't load values with an unknown key.
+ )
or
summary = StoreStep(field) and
step.store(pred, result, field)
From 59840149e8006af3a83e064ab15e9f6132661999 Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Wed, 1 Apr 2020 12:16:09 +0200
Subject: [PATCH 0035/1298] introduce a PseudoProperty type in Collections.qll
---
.../ql/src/semmle/javascript/Collections.qll | 78 +++++++++++--------
1 file changed, 45 insertions(+), 33 deletions(-)
diff --git a/javascript/ql/src/semmle/javascript/Collections.qll b/javascript/ql/src/semmle/javascript/Collections.qll
index cdb60de6a6a..d1218a577df 100644
--- a/javascript/ql/src/semmle/javascript/Collections.qll
+++ b/javascript/ql/src/semmle/javascript/Collections.qll
@@ -8,6 +8,22 @@ import javascript
private import semmle.javascript.dataflow.internal.StepSummary
private import DataFlow::PseudoProperties
+/**
+ * A pseudo-property used in a data-flow/type-tracking step for collections.
+ *
+ * By extending `TypeTrackingPseudoProperty` the class enables the use of the collection related pseudo-properties in type-tracking predicates.
+ */
+private class PseudoProperty extends TypeTrackingPseudoProperty {
+ PseudoProperty() {
+ this = [arrayLikeElement(), "1"] or // the "1" is required for the `ForOfStep`.
+ this = any(CollectionDataFlow::MapSet step).getAPseudoProperty()
+ }
+
+ override PseudoProperty getLoadStoreToProp() {
+ exists(CollectionFlowStep step | step.loadStore(_, _, this, result))
+ }
+}
+
/**
* An `AdditionalFlowStep` used to model a data-flow step related to standard library collections.
*
@@ -27,7 +43,7 @@ abstract private class CollectionFlowStep extends DataFlow::AdditionalFlowStep {
/**
* Holds if the property `prop` of the object `pred` should be loaded into `succ`.
*/
- predicate load(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
+ predicate load(DataFlow::Node pred, DataFlow::Node succ, PseudoProperty prop) { none() }
final override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
this.load(pred, succ, prop)
@@ -36,7 +52,7 @@ abstract private class CollectionFlowStep extends DataFlow::AdditionalFlowStep {
/**
* Holds if `pred` should be stored in the object `succ` under the property `prop`.
*/
- predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
+ predicate store(DataFlow::Node pred, DataFlow::Node succ, PseudoProperty prop) { none() }
final override predicate storeStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
this.store(pred, succ, prop)
@@ -45,7 +61,7 @@ abstract private class CollectionFlowStep extends DataFlow::AdditionalFlowStep {
/**
* Holds if the property `prop` should be copied from the object `pred` to the object `succ`.
*/
- predicate loadStore(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
+ predicate loadStore(DataFlow::Node pred, DataFlow::Node succ, PseudoProperty prop) { none() }
final override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
this.loadStore(pred, succ, prop, prop)
@@ -54,7 +70,9 @@ abstract private class CollectionFlowStep extends DataFlow::AdditionalFlowStep {
/**
* Holds if the property `loadProp` should be copied from the object `pred` to the property `storeProp` of object `succ`.
*/
- predicate loadStore(DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp) {
+ predicate loadStore(
+ DataFlow::Node pred, DataFlow::Node succ, PseudoProperty loadProp, PseudoProperty storeProp
+ ) {
none()
}
@@ -79,7 +97,7 @@ module CollectionsTypeTracking {
*/
pragma[inline]
DataFlow::SourceNode collectionStep(DataFlow::Node pred, StepSummary summary) {
- exists(CollectionFlowStep step, string field |
+ exists(CollectionFlowStep step, PseudoProperty field |
summary = LoadStep(field) and
step.load(pred, result, field) and
not (
@@ -93,7 +111,7 @@ module CollectionsTypeTracking {
summary = CopyStep(field) and
step.loadStore(pred, result, field)
or
- exists(string toField | summary = LoadStoreStep(field, toField) |
+ exists(PseudoProperty toField | summary = LoadStoreStep(field, toField) |
step.loadStore(pred, result, field, toField)
)
)
@@ -110,20 +128,6 @@ module CollectionsTypeTracking {
result = collectionStep(mid, summary)
)
}
-
- /**
- * A class enabling the use of the collection related pseudo-properties in type-tracking predicates.
- */
- private class MapRelatedPseudoFieldAsTypeTrackingProperty extends TypeTrackingPseudoProperty {
- MapRelatedPseudoFieldAsTypeTrackingProperty() {
- this = [setElement(), iteratorElement()] or
- any(CollectionFlowStep step).store(_, _, this)
- }
-
- override string getLoadStoreToProp() {
- exists(CollectionFlowStep step | step.loadStore(_, _, this, result))
- }
- }
}
/**
@@ -136,7 +140,7 @@ private module CollectionDataFlow {
private class SetAdd extends CollectionFlowStep, DataFlow::MethodCallNode {
SetAdd() { this.getMethodName() = "add" }
- override predicate store(DataFlow::Node element, DataFlow::Node obj, string prop) {
+ override predicate store(DataFlow::Node element, DataFlow::Node obj, PseudoProperty prop) {
obj = this.getReceiver().getALocalSource() and
element = this.getArgument(0) and
prop = setElement()
@@ -150,7 +154,7 @@ private module CollectionDataFlow {
SetConstructor() { this = DataFlow::globalVarRef("Set").getAnInstantiation() }
override predicate loadStore(
- DataFlow::Node pred, DataFlow::Node succ, string fromProp, string toProp
+ DataFlow::Node pred, DataFlow::Node succ, PseudoProperty fromProp, PseudoProperty toProp
) {
pred = this.getArgument(0) and
succ = this and
@@ -176,14 +180,14 @@ private module CollectionDataFlow {
element = DataFlow::lvalueNode(forOf.getLValue())
}
- override predicate load(DataFlow::Node obj, DataFlow::Node e, string prop) {
+ override predicate load(DataFlow::Node obj, DataFlow::Node e, PseudoProperty prop) {
obj = this and
e = element and
prop = arrayLikeElement()
}
override predicate loadStore(
- DataFlow::Node pred, DataFlow::Node succ, string fromProp, string toProp
+ DataFlow::Node pred, DataFlow::Node succ, PseudoProperty fromProp, PseudoProperty toProp
) {
pred = this and
succ = element and
@@ -198,7 +202,7 @@ private module CollectionDataFlow {
private class SetMapForEach extends CollectionFlowStep, DataFlow::MethodCallNode {
SetMapForEach() { this.getMethodName() = "forEach" }
- override predicate load(DataFlow::Node obj, DataFlow::Node element, string prop) {
+ override predicate load(DataFlow::Node obj, DataFlow::Node element, PseudoProperty prop) {
obj = this.getReceiver() and
element = this.getCallback(0).getParameter(0) and
prop = [setElement(), mapValueUnknownKey()]
@@ -207,12 +211,12 @@ private module CollectionDataFlow {
/**
* A call to the `get` method on a Map.
- * If the key of the call to `get` has a known string value, then only the value corresponding to that key will be retrieved.
+ * If the key of the call to `get` has a known string value, then only the value corresponding to that key will be retrieved. (The known string value is encoded as part of the pseudo-property)
*/
private class MapGet extends CollectionFlowStep, DataFlow::MethodCallNode {
MapGet() { this.getMethodName() = "get" }
- override predicate load(DataFlow::Node obj, DataFlow::Node element, string prop) {
+ override predicate load(DataFlow::Node obj, DataFlow::Node element, PseudoProperty prop) {
obj = this.getReceiver() and
element = this and
prop = mapValue(this.getArgument(0))
@@ -228,15 +232,23 @@ private module CollectionDataFlow {
* then the value will be saved into a pseudo-property corresponding to the known string value.
* The value will additionally be saved into a pseudo-property corresponding to values with unknown keys.
*/
- private class MapSet extends CollectionFlowStep, DataFlow::MethodCallNode {
+ class MapSet extends CollectionFlowStep, DataFlow::MethodCallNode {
MapSet() { this.getMethodName() = "set" }
- override predicate store(DataFlow::Node element, DataFlow::Node obj, string prop) {
+ override predicate store(DataFlow::Node element, DataFlow::Node obj, PseudoProperty prop) {
obj = this.getReceiver().getALocalSource() and
element = this.getArgument(1) and
- // Makes sure that both known and unknown gets will work.
- prop = [mapValue(this.getArgument(0)), mapValueUnknownKey()]
+ prop = getAPseudoProperty()
}
+
+ /**
+ * Gets a pseudo-property used to store an element in a map.
+ * The pseudo-property represents both values where the key is a known string value (which is encoded in the pseudo-property),
+ * and values where the key is unknown.
+ *
+ * The return-type is `string` as this predicate is used to define which pseudo-properties exist.
+ */
+ string getAPseudoProperty() { result = [mapValue(this.getArgument(0)), mapValueUnknownKey()] }
}
/**
@@ -246,7 +258,7 @@ private module CollectionDataFlow {
MapAndSetValues() { this.getMethodName() = "values" }
override predicate loadStore(
- DataFlow::Node pred, DataFlow::Node succ, string fromProp, string toProp
+ DataFlow::Node pred, DataFlow::Node succ, PseudoProperty fromProp, PseudoProperty toProp
) {
pred = this.getReceiver() and
succ = this and
@@ -262,7 +274,7 @@ private module CollectionDataFlow {
SetKeys() { this.getMethodName() = "keys" }
override predicate loadStore(
- DataFlow::Node pred, DataFlow::Node succ, string fromProp, string toProp
+ DataFlow::Node pred, DataFlow::Node succ, PseudoProperty fromProp, PseudoProperty toProp
) {
pred = this.getReceiver() and
succ = this and
From b1bf7f9f3d162de88d55cde328250524a5f0643a Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Wed, 1 Apr 2020 14:08:56 +0200
Subject: [PATCH 0036/1298] introduce pseudoProperty helper predicates
---
.../javascript/dataflow/Configuration.qll | 22 ++++++++++++-------
1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll
index 01a77ab1b9a..3ce7e24a384 100644
--- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll
+++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll
@@ -576,26 +576,32 @@ abstract class AdditionalFlowStep extends DataFlow::Node {
/**
* A collection of pseudo-properties that are used in multiple files.
- *
- * A pseudo-property represents the location where some value is stored in an object.
- *
+ *
+ * A pseudo-property represents the location where some value is stored in an object.
+ *
* For use with load/store steps in `DataFlow::AdditionalFlowStep` and TypeTracking.
*/
module PseudoProperties {
+ bindingset[s]
+ private string pseudoProperty(string s) { result = "$" + s + "$" }
+
+ bindingset[s, v]
+ private string pseudoProperty(string s, string v) { result = "$" + s + "|" + v + "$" }
+
/**
* Gets a pseudo-property for the location of elements in a `Set`
*/
- string setElement() { result = "$setElement$" }
+ string setElement() { result = pseudoProperty("setElement") }
/**
* Gets a pseudo-property for the location of elements in a JavaScript iterator.
*/
- string iteratorElement() { result = "$iteratorElement$" }
+ string iteratorElement() { result = pseudoProperty("iteratorElement") }
/**
* Gets a pseudo-property for the location of elements in an `Array`.
*/
- string arrayElement() { result = "$arrayElement$" }
+ string arrayElement() { result = pseudoProperty("arrayElement") }
/**
* Gets a pseudo-property for the location of elements in some array-like object. (Set, Array, or Iterator).
@@ -605,7 +611,7 @@ module PseudoProperties {
/**
* Gets a pseudo-property for the location of map values, where the key is unknown.
*/
- string mapValueUnknownKey() { result = "$UnknownMapValue$" }
+ string mapValueUnknownKey() { result = pseudoProperty("unknownMapValue") }
/**
* Gets a pseudo-property for the location of a map value where the key is `key`.
@@ -613,7 +619,7 @@ module PseudoProperties {
*/
pragma[inline]
string mapValueKnownKey(DataFlow::Node key) {
- exists(string s | key.mayHaveStringValue(s) | result = "$mapValue|" + s + "$")
+ result = pseudoProperty("mapValue", any(string s | key.mayHaveStringValue(s)))
}
/**
From 957b60f84ba05e145d30fe6e899284fdc330394b Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Wed, 1 Apr 2020 14:25:41 +0200
Subject: [PATCH 0037/1298] split fuzzy read/writes on collections into 2
pseudo-properties
---
.../ql/src/semmle/javascript/Collections.qll | 28 ++++++++-----------
.../javascript/dataflow/Configuration.qll | 5 ++++
.../frameworks/Collections/test.expected | 4 ++-
.../frameworks/Collections/tst.js | 18 ++++++++++--
4 files changed, 35 insertions(+), 20 deletions(-)
diff --git a/javascript/ql/src/semmle/javascript/Collections.qll b/javascript/ql/src/semmle/javascript/Collections.qll
index d1218a577df..3f1c8deb864 100644
--- a/javascript/ql/src/semmle/javascript/Collections.qll
+++ b/javascript/ql/src/semmle/javascript/Collections.qll
@@ -81,11 +81,6 @@ abstract private class CollectionFlowStep extends DataFlow::AdditionalFlowStep {
) {
this.loadStore(pred, succ, loadProp, storeProp)
}
-
- /**
- * Holds if this step on a collection can load a value with a known key.
- */
- predicate canLoadValueWithKnownKey() { none() }
}
/**
@@ -100,10 +95,7 @@ module CollectionsTypeTracking {
exists(CollectionFlowStep step, PseudoProperty field |
summary = LoadStep(field) and
step.load(pred, result, field) and
- not (
- step.canLoadValueWithKnownKey() and // for a step that could load a known key,
- field = mapValueUnknownKey() // don't load values with an unknown key.
- )
+ not field = mapValueUnknownKey() // prune unknown reads in type-tracking
or
summary = StoreStep(field) and
step.store(pred, result, field)
@@ -191,7 +183,7 @@ private module CollectionDataFlow {
) {
pred = this and
succ = element and
- fromProp = mapValueUnknownKey() and
+ fromProp = mapValueAll() and
toProp = "1"
}
}
@@ -205,7 +197,7 @@ private module CollectionDataFlow {
override predicate load(DataFlow::Node obj, DataFlow::Node element, PseudoProperty prop) {
obj = this.getReceiver() and
element = this.getCallback(0).getParameter(0) and
- prop = [setElement(), mapValueUnknownKey()]
+ prop = [setElement(), mapValueAll()]
}
}
@@ -219,10 +211,9 @@ private module CollectionDataFlow {
override predicate load(DataFlow::Node obj, DataFlow::Node element, PseudoProperty prop) {
obj = this.getReceiver() and
element = this and
- prop = mapValue(this.getArgument(0))
+ // reading the join of known and unknown values
+ (prop = mapValue(this.getArgument(0)) or prop = mapValueUnknownKey())
}
-
- override predicate canLoadValueWithKnownKey() { any() }
}
/**
@@ -230,7 +221,8 @@ private module CollectionDataFlow {
*
* If the key of the call to `set` has a known string value,
* then the value will be saved into a pseudo-property corresponding to the known string value.
- * The value will additionally be saved into a pseudo-property corresponding to values with unknown keys.
+ * Otherwise the value will be saved into a pseudo-property corresponding to values with unknown keys.
+ * The value will additionally be saved into a pseudo-property corresponding to all values.
*/
class MapSet extends CollectionFlowStep, DataFlow::MethodCallNode {
MapSet() { this.getMethodName() = "set" }
@@ -246,9 +238,11 @@ private module CollectionDataFlow {
* The pseudo-property represents both values where the key is a known string value (which is encoded in the pseudo-property),
* and values where the key is unknown.
*
+ * Additionally, all elements are stored into the pseudo-property `mapValueAll()`.
+ *
* The return-type is `string` as this predicate is used to define which pseudo-properties exist.
*/
- string getAPseudoProperty() { result = [mapValue(this.getArgument(0)), mapValueUnknownKey()] }
+ string getAPseudoProperty() { result = [mapValue(this.getArgument(0)), mapValueAll()] }
}
/**
@@ -262,7 +256,7 @@ private module CollectionDataFlow {
) {
pred = this.getReceiver() and
succ = this and
- fromProp = [mapValueUnknownKey(), setElement()] and
+ fromProp = [mapValueAll(), setElement()] and
toProp = iteratorElement()
}
}
diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll
index 3ce7e24a384..46aae5f12bb 100644
--- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll
+++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll
@@ -613,6 +613,11 @@ module PseudoProperties {
*/
string mapValueUnknownKey() { result = pseudoProperty("unknownMapValue") }
+ /**
+ * Gets a pseudo-property for the location of all the values in a map.
+ */
+ string mapValueAll() { result = pseudoProperty("allMapValues") }
+
/**
* Gets a pseudo-property for the location of a map value where the key is `key`.
* The string value of the `key` is encoded in the result, and there is only a result if the string value of `key` is known.
diff --git a/javascript/ql/test/library-tests/frameworks/Collections/test.expected b/javascript/ql/test/library-tests/frameworks/Collections/test.expected
index 6add9605a8d..c391fbf4f79 100644
--- a/javascript/ql/test/library-tests/frameworks/Collections/test.expected
+++ b/javascript/ql/test/library-tests/frameworks/Collections/test.expected
@@ -11,7 +11,9 @@ dataFlow
| tst.js:2:16:2:23 | source() | tst.js:46:7:46:7 | e |
| tst.js:2:16:2:23 | source() | tst.js:50:10:50:10 | e |
| tst.js:2:16:2:23 | source() | tst.js:53:8:53:21 | map.get("key") |
-| tst.js:2:16:2:23 | source() | tst.js:55:8:55:28 | map.get ... nKey()) |
+| tst.js:2:16:2:23 | source() | tst.js:59:8:59:22 | map2.get("foo") |
+| tst.js:2:16:2:23 | source() | tst.js:64:8:64:26 | map3.get(unknown()) |
+| tst.js:2:16:2:23 | source() | tst.js:69:8:69:26 | map3.get(unknown()) |
typeTracking
| tst.js:2:16:2:23 | source() | tst.js:2:16:2:23 | source() |
| tst.js:2:16:2:23 | source() | tst.js:6:14:6:14 | e |
diff --git a/javascript/ql/test/library-tests/frameworks/Collections/tst.js b/javascript/ql/test/library-tests/frameworks/Collections/tst.js
index 1a8fd2cbc07..bc7b52081d0 100644
--- a/javascript/ql/test/library-tests/frameworks/Collections/tst.js
+++ b/javascript/ql/test/library-tests/frameworks/Collections/tst.js
@@ -12,7 +12,7 @@
})
var map = new Map();
- map.set("key", source); map.set(unknownKey(), source);
+ map.set("key", source);
map.forEach(v => {
sink(v);
});
@@ -52,5 +52,19 @@
sink(map.get("key")); // NOT OK.
sink(map.get("nonExistingKey")); // OK.
- sink(map.get(unknownKey())); // NOT OK (for data-flow). OK for type-tracking.
+
+ // unknown write, known read
+ var map2 = new map();
+ map2.set(unknown(), source);
+ sink(map2.get("foo")); // NOT OK (for data-flow). OK for type-tracking.
+
+ // unknown write, unknown read
+ var map3 = new map();
+ map3.set(unknown(), source);
+ sink(map3.get(unknown())); // NOT OK (for data-flow). OK for type-tracking.
+
+ // known write, unknown read
+ var map4 = new map();
+ map4.set("foo", source);
+ sink(map3.get(unknown())); // NOT OK (for data-flow). OK for type-tracking.
})();
From 452d1d084f13afc38af8a74a4df8e6ac4b176496 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Wed, 1 Apr 2020 16:36:06 +0100
Subject: [PATCH 0038/1298] Add details about query tagging to
supported-queries.md
Add some details about query tagging (see https://wiki.semmle.com/display/IN/Query+tags and https://wiki.semmle.com/display/IN/Modelling+CWEs+at+Semmle).
---
docs/supported-queries.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/supported-queries.md b/docs/supported-queries.md
index 3ff2383ec01..fd7af7195aa 100644
--- a/docs/supported-queries.md
+++ b/docs/supported-queries.md
@@ -70,7 +70,7 @@ The process must begin with the first step and must conclude with the final step
d. Provide one or more `@tags` describing the query.
- - Tags are free-form, but we have some conventions, especially for tagging security queries with corresponding CWE numbers.
+ - Tags are free-form, but we have some conventions. At a minimum, most queries should have at least one of `correctness`, `maintainability` or `security` to indicate the general kind of issue the query is intended to find. Security queries should also be tagged with corresponding [CWE](https://cwe.mitre.org/data/definitions/1000.html) numbers, for example `external/cwe/cwe-119` (prefer the most specific CWE that encompasses the target of the query).
7. **Move your query out of `experimental`**
From 32b86ab91a3864a6ec0125902ff44c91ff98d487 Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Wed, 1 Apr 2020 20:44:47 +0200
Subject: [PATCH 0039/1298] autoformat
---
javascript/ql/src/semmle/javascript/dataflow/Configuration.qll | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll
index 46aae5f12bb..be72d9c1952 100644
--- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll
+++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll
@@ -614,7 +614,7 @@ module PseudoProperties {
string mapValueUnknownKey() { result = pseudoProperty("unknownMapValue") }
/**
- * Gets a pseudo-property for the location of all the values in a map.
+ * Gets a pseudo-property for the location of all the values in a map.
*/
string mapValueAll() { result = pseudoProperty("allMapValues") }
From 75b183bc33e909405c39bc59b23e9ff58b3fd339 Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Wed, 1 Apr 2020 20:46:49 +0200
Subject: [PATCH 0040/1298] update expected output
---
.../library-tests/Promises/tests.expected | 136 +++++++++---------
1 file changed, 68 insertions(+), 68 deletions(-)
diff --git a/javascript/ql/test/library-tests/Promises/tests.expected b/javascript/ql/test/library-tests/Promises/tests.expected
index fecf4726989..a4c7e5b163d 100644
--- a/javascript/ql/test/library-tests/Promises/tests.expected
+++ b/javascript/ql/test/library-tests/Promises/tests.expected
@@ -222,135 +222,135 @@ flow
exclusiveTaintFlow
| interflow.js:3:18:3:25 | "source" | interflow.js:18:10:18:14 | error |
typetrack
-| flow.js:20:2:20:43 | Promise ... ink(x)) | flow.js:20:36:20:42 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:20:2:20:43 | Promise ... ink(x)) | flow.js:20:36:20:42 | sink(x) | copy $PromiseResolveField$ |
| flow.js:20:2:20:43 | Promise ... ink(x)) | flow.js:20:36:20:42 | sink(x) | store $PromiseResolveField$ |
| flow.js:20:31:20:31 | x | flow.js:20:2:20:24 | Promise ... source) | load $PromiseResolveField$ |
-| flow.js:22:2:22:56 | Promise ... ink(y)) | flow.js:22:36:22:41 | foo(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:22:2:22:56 | Promise ... ink(y)) | flow.js:22:36:22:41 | foo(x) | copy $PromiseResolveField$ |
| flow.js:22:2:22:56 | Promise ... ink(y)) | flow.js:22:36:22:41 | foo(x) | store $PromiseResolveField$ |
-| flow.js:22:2:22:56 | Promise ... ink(y)) | flow.js:22:49:22:55 | sink(y) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:22:2:22:56 | Promise ... ink(y)) | flow.js:22:49:22:55 | sink(y) | copy $PromiseResolveField$ |
| flow.js:22:2:22:56 | Promise ... ink(y)) | flow.js:22:49:22:55 | sink(y) | store $PromiseResolveField$ |
| flow.js:22:31:22:31 | x | flow.js:22:2:22:24 | Promise ... source) | load $PromiseResolveField$ |
-| flow.js:24:2:24:68 | new Pro ... ink(x)) | flow.js:24:61:24:67 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:24:2:24:68 | new Pro ... ink(x)) | flow.js:24:61:24:67 | sink(x) | copy $PromiseResolveField$ |
| flow.js:24:2:24:68 | new Pro ... ink(x)) | flow.js:24:61:24:67 | sink(x) | store $PromiseResolveField$ |
| flow.js:24:56:24:56 | x | flow.js:24:2:24:49 | new Pro ... ource)) | load $PromiseResolveField$ |
-| flow.js:26:2:26:81 | new Pro ... ink(y)) | flow.js:26:61:26:66 | foo(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:26:2:26:81 | new Pro ... ink(y)) | flow.js:26:61:26:66 | foo(x) | copy $PromiseResolveField$ |
| flow.js:26:2:26:81 | new Pro ... ink(y)) | flow.js:26:61:26:66 | foo(x) | store $PromiseResolveField$ |
-| flow.js:26:2:26:81 | new Pro ... ink(y)) | flow.js:26:74:26:80 | sink(y) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:26:2:26:81 | new Pro ... ink(y)) | flow.js:26:74:26:80 | sink(y) | copy $PromiseResolveField$ |
| flow.js:26:2:26:81 | new Pro ... ink(y)) | flow.js:26:74:26:80 | sink(y) | store $PromiseResolveField$ |
| flow.js:26:56:26:56 | x | flow.js:26:2:26:49 | new Pro ... ource)) | load $PromiseResolveField$ |
-| flow.js:28:2:28:60 | Promise ... ink(z)) | flow.js:28:53:28:59 | sink(z) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:28:2:28:60 | Promise ... ink(z)) | flow.js:28:53:28:59 | sink(z) | copy $PromiseResolveField$ |
| flow.js:28:2:28:60 | Promise ... ink(z)) | flow.js:28:53:28:59 | sink(z) | store $PromiseResolveField$ |
| flow.js:28:30:28:30 | x | flow.js:28:2:28:23 | Promise ... ("foo") | load $PromiseResolveField$ |
| flow.js:28:48:28:48 | z | flow.js:28:2:28:41 | Promise ... source) | load $PromiseResolveField$ |
-| flow.js:30:2:30:60 | Promise ... ink(z)) | flow.js:30:53:30:59 | sink(z) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:30:2:30:60 | Promise ... ink(z)) | flow.js:30:53:30:59 | sink(z) | copy $PromiseResolveField$ |
| flow.js:30:2:30:60 | Promise ... ink(z)) | flow.js:30:53:30:59 | sink(z) | store $PromiseResolveField$ |
| flow.js:30:31:30:31 | x | flow.js:30:2:30:24 | Promise ... source) | load $PromiseResolveField$ |
| flow.js:30:48:30:48 | z | flow.js:30:2:30:41 | Promise ... "foo") | load $PromiseResolveField$ |
-| flow.js:32:2:32:69 | new Pro ... ink(x)) | flow.js:32:2:32:49 | new Pro ... ource)) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:32:2:32:69 | new Pro ... ink(x)) | flow.js:32:62:32:68 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:32:2:32:69 | new Pro ... ink(x)) | flow.js:32:2:32:49 | new Pro ... ource)) | copy $PromiseResolveField$ |
+| flow.js:32:2:32:69 | new Pro ... ink(x)) | flow.js:32:62:32:68 | sink(x) | copy $PromiseResolveField$ |
| flow.js:32:2:32:69 | new Pro ... ink(x)) | flow.js:32:62:32:68 | sink(x) | store $PromiseResolveField$ |
-| flow.js:34:2:34:41 | Promise ... => { }) | flow.js:34:2:34:24 | Promise ... source) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:34:2:34:60 | Promise ... ink(a)) | flow.js:34:53:34:59 | sink(a) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:34:2:34:41 | Promise ... => { }) | flow.js:34:2:34:24 | Promise ... source) | copy $PromiseResolveField$ |
+| flow.js:34:2:34:60 | Promise ... ink(a)) | flow.js:34:53:34:59 | sink(a) | copy $PromiseResolveField$ |
| flow.js:34:2:34:60 | Promise ... ink(a)) | flow.js:34:53:34:59 | sink(a) | store $PromiseResolveField$ |
| flow.js:34:48:34:48 | a | flow.js:34:2:34:41 | Promise ... => { }) | load $PromiseResolveField$ |
-| flow.js:37:11:37:29 | p5.catch(() => { }) | flow.js:36:11:36:33 | Promise ... source) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:38:11:38:31 | p6.then ... ink(a)) | flow.js:38:24:38:30 | sink(a) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:37:11:37:29 | p5.catch(() => { }) | flow.js:36:11:36:33 | Promise ... source) | copy $PromiseResolveField$ |
+| flow.js:38:11:38:31 | p6.then ... ink(a)) | flow.js:38:24:38:30 | sink(a) | copy $PromiseResolveField$ |
| flow.js:38:11:38:31 | p6.then ... ink(a)) | flow.js:38:24:38:30 | sink(a) | store $PromiseResolveField$ |
-| flow.js:40:2:40:85 | new Pro ... ink(x)) | flow.js:40:2:40:65 | new Pro ... => { }) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:40:2:40:85 | new Pro ... ink(x)) | flow.js:40:78:40:84 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:40:2:40:85 | new Pro ... ink(x)) | flow.js:40:2:40:65 | new Pro ... => { }) | copy $PromiseResolveField$ |
+| flow.js:40:2:40:85 | new Pro ... ink(x)) | flow.js:40:78:40:84 | sink(x) | copy $PromiseResolveField$ |
| flow.js:40:2:40:85 | new Pro ... ink(x)) | flow.js:40:78:40:84 | sink(x) | store $PromiseResolveField$ |
-| flow.js:42:2:42:96 | new Pro ... ink(x)) | flow.js:42:2:42:76 | new Pro ... => { }) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:42:2:42:96 | new Pro ... ink(x)) | flow.js:42:89:42:95 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:42:2:42:96 | new Pro ... ink(x)) | flow.js:42:2:42:76 | new Pro ... => { }) | copy $PromiseResolveField$ |
+| flow.js:42:2:42:96 | new Pro ... ink(x)) | flow.js:42:89:42:95 | sink(x) | copy $PromiseResolveField$ |
| flow.js:42:2:42:96 | new Pro ... ink(x)) | flow.js:42:89:42:95 | sink(x) | store $PromiseResolveField$ |
-| flow.js:44:2:44:41 | Promise ... => { }) | flow.js:44:2:44:24 | Promise ... source) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:44:2:44:58 | Promise ... => { }) | flow.js:44:2:44:41 | Promise ... => { }) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:44:2:44:75 | Promise ... => { }) | flow.js:44:2:44:58 | Promise ... => { }) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:44:2:44:94 | Promise ... ink(a)) | flow.js:44:87:44:93 | sink(a) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:44:2:44:41 | Promise ... => { }) | flow.js:44:2:44:24 | Promise ... source) | copy $PromiseResolveField$ |
+| flow.js:44:2:44:58 | Promise ... => { }) | flow.js:44:2:44:41 | Promise ... => { }) | copy $PromiseResolveField$ |
+| flow.js:44:2:44:75 | Promise ... => { }) | flow.js:44:2:44:58 | Promise ... => { }) | copy $PromiseResolveField$ |
+| flow.js:44:2:44:94 | Promise ... ink(a)) | flow.js:44:87:44:93 | sink(a) | copy $PromiseResolveField$ |
| flow.js:44:2:44:94 | Promise ... ink(a)) | flow.js:44:87:44:93 | sink(a) | store $PromiseResolveField$ |
| flow.js:44:82:44:82 | a | flow.js:44:2:44:75 | Promise ... => { }) | load $PromiseResolveField$ |
-| flow.js:46:2:46:43 | Promise ... => { }) | flow.js:46:2:46:24 | Promise ... source) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:46:2:46:62 | Promise ... ink(a)) | flow.js:46:55:46:61 | sink(a) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:46:2:46:43 | Promise ... => { }) | flow.js:46:2:46:24 | Promise ... source) | copy $PromiseResolveField$ |
+| flow.js:46:2:46:62 | Promise ... ink(a)) | flow.js:46:55:46:61 | sink(a) | copy $PromiseResolveField$ |
| flow.js:46:2:46:62 | Promise ... ink(a)) | flow.js:46:55:46:61 | sink(a) | store $PromiseResolveField$ |
| flow.js:46:50:46:50 | a | flow.js:46:2:46:43 | Promise ... => { }) | load $PromiseResolveField$ |
-| flow.js:48:2:48:56 | new Pro ... ink(x)) | flow.js:48:2:48:36 | new Pro ... urce }) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:48:2:48:56 | new Pro ... ink(x)) | flow.js:48:49:48:55 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:48:2:48:56 | new Pro ... ink(x)) | flow.js:48:2:48:36 | new Pro ... urce }) | copy $PromiseResolveField$ |
+| flow.js:48:2:48:56 | new Pro ... ink(x)) | flow.js:48:49:48:55 | sink(x) | copy $PromiseResolveField$ |
| flow.js:48:2:48:56 | new Pro ... ink(x)) | flow.js:48:49:48:55 | sink(x) | store $PromiseResolveField$ |
-| flow.js:53:2:53:41 | createP ... ink(v)) | flow.js:53:34:53:40 | sink(v) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:53:2:53:41 | createP ... ink(v)) | flow.js:53:34:53:40 | sink(v) | copy $PromiseResolveField$ |
| flow.js:53:2:53:41 | createP ... ink(v)) | flow.js:53:34:53:40 | sink(v) | store $PromiseResolveField$ |
| flow.js:53:29:53:29 | v | flow.js:53:2:53:22 | createP ... source) | load $PromiseResolveField$ |
-| flow.js:58:2:58:26 | p10.cat ... ink(x)) | flow.js:57:12:57:31 | p9.finally(() => {}) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:58:2:58:26 | p10.cat ... ink(x)) | flow.js:58:19:58:25 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:58:2:58:26 | p10.cat ... ink(x)) | flow.js:57:12:57:31 | p9.finally(() => {}) | copy $PromiseResolveField$ |
+| flow.js:58:2:58:26 | p10.cat ... ink(x)) | flow.js:58:19:58:25 | sink(x) | copy $PromiseResolveField$ |
| flow.js:58:2:58:26 | p10.cat ... ink(x)) | flow.js:58:19:58:25 | sink(x) | store $PromiseResolveField$ |
-| flow.js:62:2:62:24 | p12.cat ... ink(x)) | flow.js:61:12:61:29 | p11.then(() => {}) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:62:2:62:24 | p12.cat ... ink(x)) | flow.js:62:17:62:23 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:62:2:62:24 | p12.cat ... ink(x)) | flow.js:61:12:61:29 | p11.then(() => {}) | copy $PromiseResolveField$ |
+| flow.js:62:2:62:24 | p12.cat ... ink(x)) | flow.js:62:17:62:23 | sink(x) | copy $PromiseResolveField$ |
| flow.js:62:2:62:24 | p12.cat ... ink(x)) | flow.js:62:17:62:23 | sink(x) | store $PromiseResolveField$ |
| flow.js:65:3:65:56 | await n ... ource)) | flow.js:65:9:65:56 | new Pro ... ource)) | load $PromiseResolveField$ |
-| flow.js:76:2:76:52 | chained ... ink(e)) | flow.js:76:2:76:32 | chained ... => {}) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:76:2:76:52 | chained ... ink(e)) | flow.js:76:45:76:51 | sink(e) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:76:2:76:52 | chained ... ink(e)) | flow.js:76:2:76:32 | chained ... => {}) | copy $PromiseResolveField$ |
+| flow.js:76:2:76:52 | chained ... ink(e)) | flow.js:76:45:76:51 | sink(e) | copy $PromiseResolveField$ |
| flow.js:76:2:76:52 | chained ... ink(e)) | flow.js:76:45:76:51 | sink(e) | store $PromiseResolveField$ |
-| flow.js:79:3:79:22 | p.then(x => sink(x)) | flow.js:79:15:79:21 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:79:3:79:22 | p.then(x => sink(x)) | flow.js:79:15:79:21 | sink(x) | copy $PromiseResolveField$ |
| flow.js:79:3:79:22 | p.then(x => sink(x)) | flow.js:79:15:79:21 | sink(x) | store $PromiseResolveField$ |
-| flow.js:84:3:84:23 | p.catch ... ink(e)) | flow.js:83:32:83:32 | p | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:84:3:84:23 | p.catch ... ink(e)) | flow.js:84:16:84:22 | sink(e) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:84:3:84:23 | p.catch ... ink(e)) | flow.js:83:32:83:32 | p | copy $PromiseResolveField$ |
+| flow.js:84:3:84:23 | p.catch ... ink(e)) | flow.js:84:16:84:22 | sink(e) | copy $PromiseResolveField$ |
| flow.js:84:3:84:23 | p.catch ... ink(e)) | flow.js:84:16:84:22 | sink(e) | store $PromiseResolveField$ |
-| flow.js:89:3:89:47 | ("foo", ... ink(e)) | flow.js:89:3:89:27 | ("foo", ... => {}) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:89:3:89:47 | ("foo", ... ink(e)) | flow.js:89:40:89:46 | sink(e) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:89:3:89:47 | ("foo", ... ink(e)) | flow.js:89:3:89:27 | ("foo", ... => {}) | copy $PromiseResolveField$ |
+| flow.js:89:3:89:47 | ("foo", ... ink(e)) | flow.js:89:40:89:46 | sink(e) | copy $PromiseResolveField$ |
| flow.js:89:3:89:47 | ("foo", ... ink(e)) | flow.js:89:40:89:46 | sink(e) | store $PromiseResolveField$ |
-| flow.js:103:2:103:76 | new Pro ... ource}) | flow.js:103:2:103:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:103:2:103:95 | new Pro ... ink(x)) | flow.js:103:88:103:94 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:103:2:103:76 | new Pro ... ource}) | flow.js:103:2:103:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ |
+| flow.js:103:2:103:95 | new Pro ... ink(x)) | flow.js:103:88:103:94 | sink(x) | copy $PromiseResolveField$ |
| flow.js:103:2:103:95 | new Pro ... ink(x)) | flow.js:103:88:103:94 | sink(x) | store $PromiseResolveField$ |
| flow.js:103:83:103:83 | x | flow.js:103:2:103:76 | new Pro ... ource}) | load $PromiseResolveField$ |
-| flow.js:105:2:105:77 | new Pro ... ource}) | flow.js:105:2:105:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:105:2:105:97 | new Pro ... ink(x)) | flow.js:105:2:105:77 | new Pro ... ource}) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:105:2:105:97 | new Pro ... ink(x)) | flow.js:105:90:105:96 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:105:2:105:77 | new Pro ... ource}) | flow.js:105:2:105:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ |
+| flow.js:105:2:105:97 | new Pro ... ink(x)) | flow.js:105:2:105:77 | new Pro ... ource}) | copy $PromiseResolveField$ |
+| flow.js:105:2:105:97 | new Pro ... ink(x)) | flow.js:105:90:105:96 | sink(x) | copy $PromiseResolveField$ |
| flow.js:105:2:105:97 | new Pro ... ink(x)) | flow.js:105:90:105:96 | sink(x) | store $PromiseResolveField$ |
-| flow.js:109:2:109:71 | new Pro ... jected) | flow.js:109:2:109:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:109:2:109:91 | new Pro ... ink(x)) | flow.js:109:2:109:71 | new Pro ... jected) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:109:2:109:91 | new Pro ... ink(x)) | flow.js:109:84:109:90 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:109:2:109:71 | new Pro ... jected) | flow.js:109:2:109:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ |
+| flow.js:109:2:109:91 | new Pro ... ink(x)) | flow.js:109:2:109:71 | new Pro ... jected) | copy $PromiseResolveField$ |
+| flow.js:109:2:109:91 | new Pro ... ink(x)) | flow.js:109:84:109:90 | sink(x) | copy $PromiseResolveField$ |
| flow.js:109:2:109:91 | new Pro ... ink(x)) | flow.js:109:84:109:90 | sink(x) | store $PromiseResolveField$ |
-| flow.js:111:2:111:69 | new Pro ... jected) | flow.js:111:2:111:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:111:2:111:88 | new Pro ... ink(x)) | flow.js:111:81:111:87 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:111:2:111:69 | new Pro ... jected) | flow.js:111:2:111:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ |
+| flow.js:111:2:111:88 | new Pro ... ink(x)) | flow.js:111:81:111:87 | sink(x) | copy $PromiseResolveField$ |
| flow.js:111:2:111:88 | new Pro ... ink(x)) | flow.js:111:81:111:87 | sink(x) | store $PromiseResolveField$ |
| flow.js:111:76:111:76 | x | flow.js:111:2:111:69 | new Pro ... jected) | load $PromiseResolveField$ |
-| flow.js:113:2:113:69 | new Pro ... jected) | flow.js:113:2:113:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:113:2:113:89 | new Pro ... ink(x)) | flow.js:113:2:113:69 | new Pro ... jected) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:113:2:113:89 | new Pro ... ink(x)) | flow.js:113:82:113:88 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:113:2:113:69 | new Pro ... jected) | flow.js:113:2:113:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ |
+| flow.js:113:2:113:89 | new Pro ... ink(x)) | flow.js:113:2:113:69 | new Pro ... jected) | copy $PromiseResolveField$ |
+| flow.js:113:2:113:89 | new Pro ... ink(x)) | flow.js:113:82:113:88 | sink(x) | copy $PromiseResolveField$ |
| flow.js:113:2:113:89 | new Pro ... ink(x)) | flow.js:113:82:113:88 | sink(x) | store $PromiseResolveField$ |
-| flow.js:117:2:117:69 | new Pro ... solved) | flow.js:117:2:117:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:117:2:117:89 | new Pro ... ink(x)) | flow.js:117:2:117:69 | new Pro ... solved) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:117:2:117:89 | new Pro ... ink(x)) | flow.js:117:82:117:88 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:117:2:117:69 | new Pro ... solved) | flow.js:117:2:117:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ |
+| flow.js:117:2:117:89 | new Pro ... ink(x)) | flow.js:117:2:117:69 | new Pro ... solved) | copy $PromiseResolveField$ |
+| flow.js:117:2:117:89 | new Pro ... ink(x)) | flow.js:117:82:117:88 | sink(x) | copy $PromiseResolveField$ |
| flow.js:117:2:117:89 | new Pro ... ink(x)) | flow.js:117:82:117:88 | sink(x) | store $PromiseResolveField$ |
-| flow.js:119:2:119:69 | new Pro ... solved) | flow.js:119:2:119:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:119:2:119:88 | new Pro ... ink(x)) | flow.js:119:81:119:87 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:119:2:119:69 | new Pro ... solved) | flow.js:119:2:119:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ |
+| flow.js:119:2:119:88 | new Pro ... ink(x)) | flow.js:119:81:119:87 | sink(x) | copy $PromiseResolveField$ |
| flow.js:119:2:119:88 | new Pro ... ink(x)) | flow.js:119:81:119:87 | sink(x) | store $PromiseResolveField$ |
| flow.js:119:76:119:76 | x | flow.js:119:2:119:69 | new Pro ... solved) | load $PromiseResolveField$ |
-| flow.js:121:2:121:61 | Promise ... ink(x)) | flow.js:121:2:121:41 | Promise ... solved) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:121:2:121:61 | Promise ... ink(x)) | flow.js:121:54:121:60 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:121:2:121:61 | Promise ... ink(x)) | flow.js:121:2:121:41 | Promise ... solved) | copy $PromiseResolveField$ |
+| flow.js:121:2:121:61 | Promise ... ink(x)) | flow.js:121:54:121:60 | sink(x) | copy $PromiseResolveField$ |
| flow.js:121:2:121:61 | Promise ... ink(x)) | flow.js:121:54:121:60 | sink(x) | store $PromiseResolveField$ |
| flow.js:121:28:121:28 | x | flow.js:121:2:121:21 | Promise.resolve(123) | load $PromiseResolveField$ |
-| flow.js:123:2:123:60 | Promise ... ink(x)) | flow.js:123:53:123:59 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:123:2:123:60 | Promise ... ink(x)) | flow.js:123:53:123:59 | sink(x) | copy $PromiseResolveField$ |
| flow.js:123:2:123:60 | Promise ... ink(x)) | flow.js:123:53:123:59 | sink(x) | store $PromiseResolveField$ |
| flow.js:123:28:123:28 | x | flow.js:123:2:123:21 | Promise.resolve(123) | load $PromiseResolveField$ |
| flow.js:123:48:123:48 | x | flow.js:123:2:123:41 | Promise ... solved) | load $PromiseResolveField$ |
-| flow.js:125:2:125:61 | Promise ... ink(x)) | flow.js:125:2:125:41 | Promise ... jected) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| flow.js:125:2:125:61 | Promise ... ink(x)) | flow.js:125:54:125:60 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:125:2:125:61 | Promise ... ink(x)) | flow.js:125:2:125:41 | Promise ... jected) | copy $PromiseResolveField$ |
+| flow.js:125:2:125:61 | Promise ... ink(x)) | flow.js:125:54:125:60 | sink(x) | copy $PromiseResolveField$ |
| flow.js:125:2:125:61 | Promise ... ink(x)) | flow.js:125:54:125:60 | sink(x) | store $PromiseResolveField$ |
| flow.js:125:28:125:28 | x | flow.js:125:2:125:21 | Promise.resolve(123) | load $PromiseResolveField$ |
-| flow.js:127:2:127:60 | Promise ... ink(x)) | flow.js:127:53:127:59 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:127:2:127:60 | Promise ... ink(x)) | flow.js:127:53:127:59 | sink(x) | copy $PromiseResolveField$ |
| flow.js:127:2:127:60 | Promise ... ink(x)) | flow.js:127:53:127:59 | sink(x) | store $PromiseResolveField$ |
| flow.js:127:28:127:28 | x | flow.js:127:2:127:21 | Promise.resolve(123) | load $PromiseResolveField$ |
| flow.js:127:48:127:48 | x | flow.js:127:2:127:41 | Promise ... jected) | load $PromiseResolveField$ |
-| flow.js:129:2:129:71 | new Pro ... ink(x)) | flow.js:129:64:129:70 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:129:2:129:71 | new Pro ... ink(x)) | flow.js:129:64:129:70 | sink(x) | copy $PromiseResolveField$ |
| flow.js:129:2:129:71 | new Pro ... ink(x)) | flow.js:129:64:129:70 | sink(x) | store $PromiseResolveField$ |
| flow.js:129:59:129:59 | x | flow.js:129:2:129:52 | new Pro ... olved)) | load $PromiseResolveField$ |
-| flow.js:131:2:131:45 | Promise ... ink(x)) | flow.js:131:38:131:44 | sink(x) | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| flow.js:131:2:131:45 | Promise ... ink(x)) | flow.js:131:38:131:44 | sink(x) | copy $PromiseResolveField$ |
| flow.js:131:2:131:45 | Promise ... ink(x)) | flow.js:131:38:131:44 | sink(x) | store $PromiseResolveField$ |
| flow.js:131:33:131:33 | x | flow.js:131:2:131:26 | Promise ... solved) | load $PromiseResolveField$ |
-| interflow.js:6:3:9:23 | loadScr ... eError) | interflow.js:6:3:8:26 | loadScr ... () { }) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| promises.js:23:3:25:4 | promise ... v;\\n }) | promises.js:10:18:17:4 | new Pro ... );\\n }) | copy $PromiseResolveField$ to $PromiseResolveField$ |
-| promises.js:33:19:35:6 | new Pro ... \\n }) | promises.js:34:17:34:22 | source | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| interflow.js:6:3:9:23 | loadScr ... eError) | interflow.js:6:3:8:26 | loadScr ... () { }) | copy $PromiseResolveField$ |
+| promises.js:23:3:25:4 | promise ... v;\\n }) | promises.js:10:18:17:4 | new Pro ... );\\n }) | copy $PromiseResolveField$ |
+| promises.js:33:19:35:6 | new Pro ... \\n }) | promises.js:34:17:34:22 | source | copy $PromiseResolveField$ |
| promises.js:33:19:35:6 | new Pro ... \\n }) | promises.js:34:17:34:22 | source | store $PromiseResolveField$ |
-| promises.js:43:19:45:6 | Q.Promi ... \\n }) | promises.js:44:17:44:22 | source | copy $PromiseResolveField$ to $PromiseResolveField$ |
+| promises.js:43:19:45:6 | Q.Promi ... \\n }) | promises.js:44:17:44:22 | source | copy $PromiseResolveField$ |
| promises.js:43:19:45:6 | Q.Promi ... \\n }) | promises.js:44:17:44:22 | source | store $PromiseResolveField$ |
| promises.js:71:34:71:36 | val | promises.js:71:5:71:27 | Promise ... source) | load $PromiseResolveField$ |
| promises.js:72:48:72:50 | val | promises.js:72:5:72:41 | new Pro ... ource)) | load $PromiseResolveField$ |
From af9e05b9cdbd0e892804e3a75b9b46e92f35bcb2 Mon Sep 17 00:00:00 2001
From: Mathias Vorreiter Pedersen
Date: Thu, 2 Apr 2020 10:57:11 +0200
Subject: [PATCH 0041/1298] C++: Accept test
---
.../dataflow/dataflow-tests/test_diff.expected | 4 ----
.../dataflow/dataflow-tests/test_ir.expected | 4 ++++
.../library-tests/dataflow/taint-tests/taint.cpp | 16 ++++++++--------
.../dataflow/taint-tests/test_diff.expected | 12 +++++++++---
.../dataflow/taint-tests/test_ir.expected | 12 ++++++++++++
5 files changed, 33 insertions(+), 15 deletions(-)
diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected
index 71630f892f5..8dae5a8dad8 100644
--- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected
+++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected
@@ -31,10 +31,6 @@
| ref.cpp:53:17:53:18 | ref.cpp:62:10:62:11 | AST only |
| ref.cpp:53:21:53:22 | ref.cpp:65:10:65:11 | AST only |
| ref.cpp:55:23:55:28 | ref.cpp:56:10:56:11 | AST only |
-| ref.cpp:94:15:94:20 | ref.cpp:129:13:129:15 | AST only |
-| ref.cpp:109:15:109:20 | ref.cpp:132:13:132:15 | AST only |
-| ref.cpp:122:23:122:28 | ref.cpp:123:13:123:15 | AST only |
-| ref.cpp:125:19:125:24 | ref.cpp:126:13:126:15 | AST only |
| test.cpp:75:7:75:8 | test.cpp:76:8:76:9 | AST only |
| test.cpp:83:7:83:8 | test.cpp:84:8:84:18 | AST only |
| test.cpp:83:7:83:8 | test.cpp:86:8:86:9 | AST only |
diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected
index 275cbabc075..202d9827323 100644
--- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected
+++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected
@@ -39,6 +39,10 @@
| globals.cpp:12:10:12:24 | flowTestGlobal1 | globals.cpp:13:23:13:28 | call to source |
| globals.cpp:19:10:19:24 | flowTestGlobal2 | globals.cpp:23:23:23:28 | call to source |
| lambdas.cpp:35:8:35:8 | a | lambdas.cpp:8:10:8:15 | call to source |
+| ref.cpp:123:13:123:15 | val | ref.cpp:122:23:122:28 | call to source |
+| ref.cpp:126:13:126:15 | val | ref.cpp:125:19:125:24 | call to source |
+| ref.cpp:129:13:129:15 | val | ref.cpp:94:15:94:20 | call to source |
+| ref.cpp:132:13:132:15 | val | ref.cpp:109:15:109:20 | call to source |
| test.cpp:7:8:7:9 | t1 | test.cpp:6:12:6:17 | call to source |
| test.cpp:9:8:9:9 | t1 | test.cpp:6:12:6:17 | call to source |
| test.cpp:10:8:10:9 | t2 | test.cpp:6:12:6:17 | call to source |
diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp
index 5d8327017fa..efcd600e21e 100644
--- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp
+++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp
@@ -85,14 +85,14 @@ void class_field_test() {
mc1.myMethod();
- sink(mc1.a);
- sink(mc1.b); // tainted [NOT DETECTED with IR]
- sink(mc1.c); // tainted [NOT DETECTED with IR]
- sink(mc1.d); // tainted [NOT DETECTED with IR]
- sink(mc2.a);
- sink(mc2.b); // tainted [NOT DETECTED with IR]
- sink(mc2.c); // tainted [NOT DETECTED with IR]
- sink(mc2.d);
+ sink(mc1.a); // [FALSE POSITIVE]
+ sink(mc1.b); // tainted
+ sink(mc1.c); // tainted
+ sink(mc1.d); // tainted
+ sink(mc2.a); // [FALSE POSITIVE]
+ sink(mc2.b); // tainted
+ sink(mc2.c); // tainted
+ sink(mc2.d); // [FALSE POSITIVE]
}
// --- arrays ---
diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected
index 329a0bb6ecc..9789a2bda21 100644
--- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected
+++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected
@@ -11,11 +11,17 @@
| taint.cpp:41:7:41:13 | taint.cpp:35:12:35:17 | AST only |
| taint.cpp:42:7:42:13 | taint.cpp:35:12:35:17 | AST only |
| taint.cpp:43:7:43:13 | taint.cpp:37:22:37:27 | AST only |
+| taint.cpp:88:11:88:11 | taint.cpp:77:7:77:12 | IR only |
| taint.cpp:89:11:89:11 | taint.cpp:71:22:71:27 | AST only |
+| taint.cpp:89:11:89:11 | taint.cpp:77:7:77:12 | IR only |
| taint.cpp:90:11:90:11 | taint.cpp:72:7:72:12 | AST only |
-| taint.cpp:91:11:91:11 | taint.cpp:77:7:77:12 | AST only |
-| taint.cpp:93:11:93:11 | taint.cpp:71:22:71:27 | AST only |
-| taint.cpp:94:11:94:11 | taint.cpp:72:7:72:12 | AST only |
+| taint.cpp:90:11:90:11 | taint.cpp:77:7:77:12 | IR only |
+| taint.cpp:92:11:92:11 | taint.cpp:71:22:71:27 | IR only |
+| taint.cpp:92:11:92:11 | taint.cpp:72:7:72:12 | IR only |
+| taint.cpp:93:11:93:11 | taint.cpp:72:7:72:12 | IR only |
+| taint.cpp:94:11:94:11 | taint.cpp:71:22:71:27 | IR only |
+| taint.cpp:95:11:95:11 | taint.cpp:71:22:71:27 | IR only |
+| taint.cpp:95:11:95:11 | taint.cpp:72:7:72:12 | IR only |
| taint.cpp:109:7:109:13 | taint.cpp:105:12:105:17 | IR only |
| taint.cpp:130:7:130:9 | taint.cpp:127:8:127:13 | IR only |
| taint.cpp:137:7:137:9 | taint.cpp:120:11:120:16 | AST only |
diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected
index b0107791e61..751775e21ab 100644
--- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected
+++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected
@@ -1,6 +1,18 @@
| taint.cpp:8:8:8:13 | clean1 | taint.cpp:4:27:4:33 | source1 |
| taint.cpp:16:8:16:14 | source1 | taint.cpp:12:22:12:27 | call to source |
| taint.cpp:17:8:17:16 | ++ ... | taint.cpp:12:22:12:27 | call to source |
+| taint.cpp:88:11:88:11 | a | taint.cpp:77:7:77:12 | call to source |
+| taint.cpp:89:11:89:11 | b | taint.cpp:77:7:77:12 | call to source |
+| taint.cpp:90:11:90:11 | c | taint.cpp:77:7:77:12 | call to source |
+| taint.cpp:91:11:91:11 | d | taint.cpp:77:7:77:12 | call to source |
+| taint.cpp:92:11:92:11 | a | taint.cpp:71:22:71:27 | call to source |
+| taint.cpp:92:11:92:11 | a | taint.cpp:72:7:72:12 | call to source |
+| taint.cpp:93:11:93:11 | b | taint.cpp:71:22:71:27 | call to source |
+| taint.cpp:93:11:93:11 | b | taint.cpp:72:7:72:12 | call to source |
+| taint.cpp:94:11:94:11 | c | taint.cpp:71:22:71:27 | call to source |
+| taint.cpp:94:11:94:11 | c | taint.cpp:72:7:72:12 | call to source |
+| taint.cpp:95:11:95:11 | d | taint.cpp:71:22:71:27 | call to source |
+| taint.cpp:95:11:95:11 | d | taint.cpp:72:7:72:12 | call to source |
| taint.cpp:109:7:109:13 | access to array | taint.cpp:105:12:105:17 | call to source |
| taint.cpp:129:7:129:9 | * ... | taint.cpp:120:11:120:16 | call to source |
| taint.cpp:130:7:130:9 | * ... | taint.cpp:127:8:127:13 | call to source |
From dda3aaa8aaf4c89fe735a534a40566348d656125 Mon Sep 17 00:00:00 2001
From: Mathias Vorreiter Pedersen
Date: Thu, 2 Apr 2020 14:00:33 +0200
Subject: [PATCH 0042/1298] C++: Add QLDoc to public classes and predicates
---
.../cpp/ir/dataflow/internal/DataFlowUtil.qll | 44 +++++++++++++++++--
1 file changed, 41 insertions(+), 3 deletions(-)
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
index 367d49bb2a7..5eba5108983 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
@@ -63,6 +63,14 @@ class Node extends TIRDataFlowNode {
*/
Variable asVariable() { result = this.(VariableNode).getVariable() }
+ /**
+ * Gets the expression that is partially defined by this node, if any.
+ *
+ * Partial definitions are created for field stores (`x.y = taint();` is a partial
+ * definition of `x`), and for calls that may change the value of an object (so
+ * `x.set(taint())` is a partial definition of `x`, and `transfer(&x, taint())` is
+ * a partial definition of `&x`).
+ */
Expr asPartialDefinition() {
result = this.(PartialDefinitionNode).getInstruction().getUnconvertedResultExpression()
}
@@ -100,6 +108,9 @@ class Node extends TIRDataFlowNode {
string toString() { none() } // overridden by subclasses
}
+/**
+ * An instruction, viewed as a node in a data flow graph.
+ */
class InstructionNode extends Node, TInstructionNode {
Instruction instr;
@@ -146,12 +157,16 @@ class ExprNode extends InstructionNode {
override string toString() { result = this.asConvertedExpr().toString() }
}
+/**
+ * A node representing a `Parameter`. This includes both explicit parameters such
+ * as `x` in `f(x)` and implicit parameters such as `this` in `x.f()`
+ */
class ParameterNode extends InstructionNode {
/**
* Holds if this node is the parameter of `c` at the specified (zero-based)
* position. The implicit `this` parameter is considered to have index `-1`.
*/
- predicate isParameterOf(Function f, int i) { none() }
+ predicate isParameterOf(Function f, int i) { none() } // overriden by subclasses
}
/**
@@ -163,6 +178,7 @@ private class ExplicitParameterNode extends ParameterNode {
override predicate isParameterOf(Function f, int i) { f.getParameter(i) = instr.getParameter() }
+ /** Gets the parameter corresponding to this node. */
Parameter getParameter() { result = instr.getParameter() }
override string toString() { result = instr.getParameter().toString() }
@@ -216,7 +232,25 @@ abstract class PostUpdateNode extends InstructionNode {
abstract Node getPreUpdateNode();
}
-abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode {
+/**
+ * The base class for nodes that perform "partial definitions".
+ *
+ * In contrast to a normal "definition", which provides a new value for
+ * something, a partial definition is an expression that may affect a
+ * value, but does not necessarily replace it entirely. For example:
+ * ```
+ * x.y = 1; // a partial definition of the object `x`.
+ * x.y.z = 1; // a partial definition of the object `x.y`.
+ * x.setY(1); // a partial definition of the object `x`.
+ * setY(&x); // a partial definition of the object `x`.
+ * ```
+ */
+abstract class PartialDefinitionNode extends PostUpdateNode, TInstructionNode {
+ /**
+ * Gets the instruction that partially defines the object. This includes
+ * both the instruction that partially defines the object, and the chi
+ * instruction that links up the partial definition to the object.
+ */
final Instruction getInstructionOrChi() {
exists(ChiInstruction chi |
not chi.isResultConflated() and
@@ -228,7 +262,7 @@ abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructio
}
}
-class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
+private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
override StoreInstruction instr;
FieldAddressInstruction field;
@@ -310,6 +344,10 @@ class VariableNode extends Node, TVariableNode {
*/
InstructionNode instructionNode(Instruction instr) { result.getInstruction() = instr }
+/**
+ * Gets the `Node` corresponding to a definition by reference of the variable
+ * that is passed as `argument` of a call.
+ */
DefinitionByReferenceNode definitionByReferenceNode(Expr e) { result.getArgument() = e }
/**
From 2c0bae4937933fc7a7a78c261c739bcda4881327 Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Thu, 2 Apr 2020 20:28:04 +0200
Subject: [PATCH 0043/1298] Apply suggestions from code review
Co-Authored-By: Esben Sparre Andreasen
---
javascript/ql/src/semmle/javascript/Collections.qll | 8 ++++----
.../ql/src/semmle/javascript/dataflow/Configuration.qll | 2 +-
.../semmle/javascript/dataflow/internal/StepSummary.qll | 2 +-
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/javascript/ql/src/semmle/javascript/Collections.qll b/javascript/ql/src/semmle/javascript/Collections.qll
index 3f1c8deb864..19a26d7da35 100644
--- a/javascript/ql/src/semmle/javascript/Collections.qll
+++ b/javascript/ql/src/semmle/javascript/Collections.qll
@@ -84,7 +84,7 @@ abstract private class CollectionFlowStep extends DataFlow::AdditionalFlowStep {
}
/**
- * A collection of predicates and clases for type-tracking collections.
+ * Provides predicates and clases for type-tracking collections.
*/
module CollectionsTypeTracking {
/**
@@ -220,9 +220,9 @@ private module CollectionDataFlow {
* A call to the `set` method on a Map.
*
* If the key of the call to `set` has a known string value,
- * then the value will be saved into a pseudo-property corresponding to the known string value.
- * Otherwise the value will be saved into a pseudo-property corresponding to values with unknown keys.
- * The value will additionally be saved into a pseudo-property corresponding to all values.
+ * then the value will be stored into a pseudo-property corresponding to the known string value.
+ * Otherwise the value will be stored into a pseudo-property corresponding to values with unknown keys.
+ * The value will additionally be stored into a pseudo-property corresponding to all values.
*/
class MapSet extends CollectionFlowStep, DataFlow::MethodCallNode {
MapSet() { this.getMethodName() = "set" }
diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll
index be72d9c1952..5c583c38764 100644
--- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll
+++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll
@@ -611,7 +611,7 @@ module PseudoProperties {
/**
* Gets a pseudo-property for the location of map values, where the key is unknown.
*/
- string mapValueUnknownKey() { result = pseudoProperty("unknownMapValue") }
+ string mapValueUnknownKey() { result = pseudoProperty("mapValueUnknownKey") }
/**
* Gets a pseudo-property for the location of all the values in a map.
diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll
index c4465285109..92e05e4b927 100644
--- a/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll
+++ b/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll
@@ -66,7 +66,7 @@ class StepSummary extends TStepSummary {
exists(string prop | this = CopyStep(prop) | result = "copy " + prop)
or
exists(string fromProp, string toProp | this = LoadStoreStep(fromProp, toProp) |
- result = "copy " + fromProp + " to " + toProp
+ result = "load " + fromProp + " and store to " + toProp
)
}
}
From 845020d2aee88b8e48d835117e3619cb108004f4 Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Thu, 2 Apr 2020 20:26:47 +0200
Subject: [PATCH 0044/1298] change getReceiver to getAMethodCall
---
javascript/ql/src/semmle/javascript/Collections.qll | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/javascript/ql/src/semmle/javascript/Collections.qll b/javascript/ql/src/semmle/javascript/Collections.qll
index 19a26d7da35..a0319391890 100644
--- a/javascript/ql/src/semmle/javascript/Collections.qll
+++ b/javascript/ql/src/semmle/javascript/Collections.qll
@@ -133,7 +133,7 @@ private module CollectionDataFlow {
SetAdd() { this.getMethodName() = "add" }
override predicate store(DataFlow::Node element, DataFlow::Node obj, PseudoProperty prop) {
- obj = this.getReceiver().getALocalSource() and
+ this = obj.(DataFlow::SourceNode).getAMethodCall() and
element = this.getArgument(0) and
prop = setElement()
}
@@ -228,7 +228,7 @@ private module CollectionDataFlow {
MapSet() { this.getMethodName() = "set" }
override predicate store(DataFlow::Node element, DataFlow::Node obj, PseudoProperty prop) {
- obj = this.getReceiver().getALocalSource() and
+ this = obj.(DataFlow::SourceNode).getAMethodCall() and
element = this.getArgument(1) and
prop = getAPseudoProperty()
}
From 6517feda9a4931c5c6a7566c1e9ef4c4829a04f3 Mon Sep 17 00:00:00 2001
From: Rebecca Valentine
Date: Thu, 2 Apr 2020 11:56:15 -0700
Subject: [PATCH 0045/1298] Python: ObjectAPI to ValueAPI:
WrongNumberArgumentsInCall: Adds new version of ObjectsAPI.qll
---
.../src/semmle/python/objects/ObjectAPI.qll | 711 ++++++++----------
1 file changed, 294 insertions(+), 417 deletions(-)
diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll
index 4b8aaaa45b8..380f42043c7 100644
--- a/python/ql/src/semmle/python/objects/ObjectAPI.qll
+++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll
@@ -3,9 +3,6 @@
* A `Value` is a static approximation to a set of runtime objects.
*/
-
-
-
import python
private import TObject
private import semmle.python.objects.ObjectInternal
@@ -14,54 +11,48 @@ private import semmle.python.pointsto.PointsToContext
private import semmle.python.pointsto.MRO
private import semmle.python.types.Builtins
-/* Use the term `ObjectSource` to refer to DB entity. Either a CFG node
+/*
+ * Use the term `ObjectSource` to refer to DB entity. Either a CFG node
* for Python objects, or `@py_cobject` entity for built-in objects.
*/
+
class ObjectSource = Object;
/* Aliases for scopes */
class FunctionScope = Function;
+
class ClassScope = Class;
+
class ModuleScope = Module;
-/** Class representing values in the Python program
+/**
+ * Class representing values in the Python program
* Each `Value` is a static approximation to a set of one or more real objects.
*/
class Value extends TObject {
-
Value() {
this != ObjectInternal::unknown() and
this != ObjectInternal::unknownClass() and
this != ObjectInternal::undefined()
}
- string toString() {
- result = this.(ObjectInternal).toString()
- }
+ string toString() { result = this.(ObjectInternal).toString() }
/** Gets a `ControlFlowNode` that refers to this object. */
- ControlFlowNode getAReference() {
- PointsToInternal::pointsTo(result, _, this, _)
- }
+ ControlFlowNode getAReference() { PointsToInternal::pointsTo(result, _, this, _) }
/** Gets the origin CFG node for this value. */
- ControlFlowNode getOrigin() {
- result = this.(ObjectInternal).getOrigin()
- }
+ ControlFlowNode getOrigin() { result = this.(ObjectInternal).getOrigin() }
-
- /** Gets the class of this object.
+ /**
+ * Gets the class of this object.
* Strictly, the `Value` representing the class of the objects
* represented by this Value.
*/
- ClassValue getClass() {
- result = this.(ObjectInternal).getClass()
- }
+ ClassValue getClass() { result = this.(ObjectInternal).getClass() }
/** Gets a call to this object */
- CallNode getACall() {
- result = this.getACall(_)
- }
+ CallNode getACall() { result = this.getACall(_) }
/** Gets a call to this object with the given `caller` context. */
CallNode getACall(PointsToContext caller) {
@@ -74,36 +65,34 @@ class Value extends TObject {
}
/** Gets a `Value` that represents the attribute `name` of this object. */
- Value attr(string name) {
- this.(ObjectInternal).attribute(name, result, _)
- }
+ Value attr(string name) { this.(ObjectInternal).attribute(name, result, _) }
- /** Holds if this value is builtin. Applies to built-in functions and methods,
+ /**
+ * Holds if this value is builtin. Applies to built-in functions and methods,
* but also integers and strings.
*/
- predicate isBuiltin() {
- this.(ObjectInternal).isBuiltin()
- }
+ predicate isBuiltin() { this.(ObjectInternal).isBuiltin() }
predicate hasLocationInfo(string filepath, int bl, int bc, int el, int ec) {
this.(ObjectInternal).getOrigin().getLocation().hasLocationInfo(filepath, bl, bc, el, ec)
or
not exists(this.(ObjectInternal).getOrigin()) and
- filepath = "" and bl = 0 and bc = 0 and el = 0 and ec = 0
+ filepath = "" and
+ bl = 0 and
+ bc = 0 and
+ el = 0 and
+ ec = 0
}
- /** Gets the name of this value, if it has one.
+ /**
+ * Gets the name of this value, if it has one.
* Note this is the innate name of the
* object, not necessarily all the names by which it can be called.
*/
- final string getName() {
- result = this.(ObjectInternal).getName()
- }
+ final string getName() { result = this.(ObjectInternal).getName() }
/** Holds if this value has the attribute `name` */
- predicate hasAttribute(string name) {
- this.(ObjectInternal).hasAttribute(name)
- }
+ predicate hasAttribute(string name) { this.(ObjectInternal).hasAttribute(name) }
/** Whether this value is absent from the database, but has been inferred to likely exist */
predicate isAbsent() {
@@ -112,9 +101,10 @@ class Value extends TObject {
this instanceof AbsentModuleAttributeObjectInternal
}
- /** Whether this overrides v. In this context, "overrides" means that this object
- * is a named attribute of a some class C and `v` is a named attribute of another
- * class S, both attributes having the same name, and S is a super class of C.
+ /**
+ * Whether this overrides v. In this context, "overrides" means that this object
+ * is a named attribute of a some class C and `v` is a named attribute of another
+ * class S, both attributes having the same name, and S is a super class of C.
*/
predicate overrides(Value v) {
exists(ClassValue my_class, ClassValue other_class, string name |
@@ -124,46 +114,42 @@ class Value extends TObject {
)
}
- /** Gets the boolean interpretation of this value.
- * Could be both `true` and `false`, if we can't determine the result more precisely.
- */
- boolean getABooleanValue() {
- result = this.(ObjectInternal).booleanValue()
- }
+ /**
+ * Gets the boolean interpretation of this value.
+ * Could be both `true` and `false`, if we can't determine the result more precisely.
+ */
+ boolean getABooleanValue() { result = this.(ObjectInternal).booleanValue() }
- /** Gets the boolean interpretation of this value, only if we can determine the result precisely.
- * The result can be `none()`, but never both `true` and `false`.
- */
+ /**
+ * Gets the boolean interpretation of this value, only if we can determine the result precisely.
+ * The result can be `none()`, but never both `true` and `false`.
+ */
boolean getDefiniteBooleanValue() {
result = getABooleanValue() and
not (getABooleanValue() = true and getABooleanValue() = false)
}
}
-/** Class representing modules in the Python program
+/**
+ * Class representing modules in the Python program
* Each `ModuleValue` represents a module object in the Python program.
*/
class ModuleValue extends Value {
+ ModuleValue() { this instanceof ModuleObjectInternal }
- ModuleValue() {
- this instanceof ModuleObjectInternal
- }
-
- /** Holds if this module "exports" name.
+ /**
+ * Holds if this module "exports" name.
* That is, does it define `name` in `__all__` or is
* `__all__` not defined and `name` a global variable that does not start with "_"
* This is the set of names imported by `from ... import *`.
*/
- predicate exports(string name) {
- PointsTo::moduleExports(this, name)
- }
+ predicate exports(string name) { PointsTo::moduleExports(this, name) }
/** Gets the scope for this module, provided that it is a Python module. */
- ModuleScope getScope() {
- result = this.(ModuleObjectInternal).getSourceModule()
- }
+ ModuleScope getScope() { result = this.(ModuleObjectInternal).getSourceModule() }
- /** Gets the container path for this module. Will be the file for a Python module,
+ /**
+ * Gets the container path for this module. Will be the file for a Python module,
* the folder for a package and no result for a builtin module.
*/
Container getPath() {
@@ -172,26 +158,20 @@ class ModuleValue extends Value {
result = this.(PythonModuleObjectInternal).getSourceModule().getFile()
}
- /** Whether this module is imported by 'import name'. For example on a linux system,
- * the module 'posixpath' is imported as 'os.path' or as 'posixpath' */
- predicate importedAs(string name) {
- PointsToInternal::module_imported_as(this, name)
- }
+ /**
+ * Whether this module is imported by 'import name'. For example on a linux system,
+ * the module 'posixpath' is imported as 'os.path' or as 'posixpath'
+ */
+ predicate importedAs(string name) { PointsToInternal::module_imported_as(this, name) }
/** Whether this module is a package. */
- predicate isPackage() {
- this instanceof PackageObjectInternal
- }
+ predicate isPackage() { this instanceof PackageObjectInternal }
/** Whether the complete set of names "exported" by this module can be accurately determined */
- predicate hasCompleteExportInfo() {
- this.(ModuleObjectInternal).hasCompleteExportInfo()
- }
+ predicate hasCompleteExportInfo() { this.(ModuleObjectInternal).hasCompleteExportInfo() }
/** Get a module that this module imports */
- ModuleValue getAnImportedModule() {
- result.importedAs(this.getScope().getAnImportedModuleName())
- }
+ ModuleValue getAnImportedModule() { result.importedAs(this.getScope().getAnImportedModuleName()) }
/** When used as a normal module (for example, imported and used by other modules) */
predicate isUsedAsModule() {
@@ -214,7 +194,8 @@ class ModuleValue extends Value {
i.getScope() = this.getScope() and
op instanceof Eq and
i.getTest().(Compare).compares(name, op, main) and
- name.getId() = "__name__" and main.getText() = "__main__"
+ name.getId() = "__name__" and
+ main.getText() = "__main__"
)
or
exists(Comment c |
@@ -227,8 +208,8 @@ class ModuleValue extends Value {
}
module Module {
-
- /** Gets the `ModuleValue` named `name`.
+ /**
+ * Gets the `ModuleValue` named `name`.
*
* Note that the name used to refer to a module is not
* necessarily its name. For example,
@@ -245,25 +226,23 @@ module Module {
/* Prevent runaway recursion when a module has itself as an attribute. */
private ModuleValue named(string name, int dots) {
- dots = 0 and not name.charAt(_) = "." and
+ dots = 0 and
+ not name.charAt(_) = "." and
result.getName() = name
or
dots <= 3 and
- exists(string modname, string attrname |
- name = modname + "." + attrname |
- result = named(modname, dots-1).attr(attrname)
+ exists(string modname, string attrname | name = modname + "." + attrname |
+ result = named(modname, dots - 1).attr(attrname)
)
}
/** Get the `ModuleValue` for the `builtin` module. */
- ModuleValue builtinModule() {
- result = TBuiltinModuleObject(Builtin::builtinModule())
- }
+ ModuleValue builtinModule() { result = TBuiltinModuleObject(Builtin::builtinModule()) }
}
module Value {
-
- /** Gets the `Value` named `name`.
+ /**
+ * Gets the `Value` named `name`.
* If there is at least one '.' in `name`, then the part of
* the name to the left of the rightmost '.' is interpreted as a module name
* and the part after the rightmost '.' as an attribute of that module.
@@ -274,8 +253,7 @@ module Value {
* For example `Value::named("len")` is the `Value` representing the `len` built-in function.
*/
Value named(string name) {
- exists(string modname, string attrname |
- name = modname + "." + attrname |
+ exists(string modname, string attrname | name = modname + "." + attrname |
result = Module::named(modname).attr(attrname)
)
or
@@ -288,34 +266,32 @@ module Value {
name = "False" and result = TFalse()
}
- /** Gets the `NumericValue` for the integer constant `i`, if it exists.
+ /**
+ * Gets the `NumericValue` for the integer constant `i`, if it exists.
* There will be no `NumericValue` for most integers, but the following are
* guaranteed to exist:
* * From zero to 511 inclusive.
* * All powers of 2 (up to 2**30)
* * Any integer explicitly mentioned in the source program.
*/
- NumericValue forInt(int i) {
- result.(IntObjectInternal).intValue() = i
- }
+ NumericValue forInt(int i) { result.(IntObjectInternal).intValue() = i }
- /** Gets the `Value` for the bytes constant `bytes`, if it exists.
+ /**
+ * Gets the `Value` for the bytes constant `bytes`, if it exists.
* There will be no `Value` for most byte strings, unless it is explicitly
* declared in the source program.
*/
- StringValue forBytes(string bytes) {
- result.(BytesObjectInternal).strValue() = bytes
- }
+ StringValue forBytes(string bytes) { result.(BytesObjectInternal).strValue() = bytes }
- /** Gets the `Value` for the unicode constant `text`, if it exists.
+ /**
+ * Gets the `Value` for the unicode constant `text`, if it exists.
* There will be no `Value` for most text strings, unless it is explicitly
* declared in the source program.
*/
- StringValue forUnicode(string text) {
- result.(UnicodeObjectInternal).strValue() = text
- }
+ StringValue forUnicode(string text) { result.(UnicodeObjectInternal).strValue() = text }
- /** Gets a `Value` for the string `text`. May be a bytes or unicode string for Python 2.
+ /**
+ * Gets a `Value` for the string `text`. May be a bytes or unicode string for Python 2.
* There will be no `Value` for most strings, unless it is explicitly
* declared in the source program.
*/
@@ -334,9 +310,7 @@ module Value {
}
/** Gets the `Value` for `None`. */
- Value none_() {
- result = ObjectInternal::none_()
- }
+ Value none_() { result = ObjectInternal::none_() }
/**
* Shorcuts added by the `site` module to exit your interactive session.
@@ -353,32 +327,25 @@ module Value {
}
}
-/** Class representing callables in the Python program
+/**
+ * Class representing callables in the Python program
* Callables include Python functions, built-in functions and bound-methods,
* but not classes.
*/
class CallableValue extends Value {
+ CallableValue() { this instanceof CallableObjectInternal }
- CallableValue() {
- this instanceof CallableObjectInternal
- }
-
- /** Holds if this callable never returns once called.
+ /**
+ * Holds if this callable never returns once called.
* For example, `sys.exit`
*/
- predicate neverReturns() {
- this.(CallableObjectInternal).neverReturns()
- }
+ predicate neverReturns() { this.(CallableObjectInternal).neverReturns() }
/** Gets the scope for this function, provided that it is a Python function. */
- FunctionScope getScope() {
- result = this.(PythonFunctionObjectInternal).getScope()
- }
+ FunctionScope getScope() { result = this.(PythonFunctionObjectInternal).getScope() }
/** Gets the `n`th parameter node of this callable. */
- NameNode getParameter(int n) {
- result = this.(CallableObjectInternal).getParameter(n)
- }
+ NameNode getParameter(int n) { result = this.(CallableObjectInternal).getParameter(n) }
/** Gets the `name`d parameter node of this callable. */
NameNode getParameterByName(string name) {
@@ -386,56 +353,60 @@ class CallableValue extends Value {
}
/** Gets the argument corresponding to the `n'th parameter node of this callable. */
- cached ControlFlowNode getArgumentForCall(CallNode call, int n) {
+ cached
+ ControlFlowNode getArgumentForCall(CallNode call, int n) {
exists(ObjectInternal called, int offset |
PointsToInternal::pointsTo(call.getFunction(), _, called, _) and
called.functionAndOffset(this, offset)
- |
- call.getArg(n-offset) = result
+ |
+ call.getArg(n - offset) = result
or
- exists(string name | call.getArgByName(name) = result and this.(PythonFunctionObjectInternal).getScope().getArg(n+offset).getName() = name)
+ exists(string name |
+ call.getArgByName(name) = result and
+ this.(PythonFunctionObjectInternal).getScope().getArg(n + offset).getName() = name
+ )
or
called instanceof BoundMethodObjectInternal and
- offset = 1 and n = 0 and result = call.getFunction().(AttrNode).getObject()
+ offset = 1 and
+ n = 0 and
+ result = call.getFunction().(AttrNode).getObject()
)
}
-
/** Gets the argument corresponding to the `name`d parameter node of this callable. */
- cached ControlFlowNode getNamedArgumentForCall(CallNode call, string name) {
+ cached
+ ControlFlowNode getNamedArgumentForCall(CallNode call, string name) {
exists(CallableObjectInternal called, int offset |
PointsToInternal::pointsTo(call.getFunction(), _, called, _) and
called.functionAndOffset(this, offset)
- |
+ |
exists(int n |
call.getArg(n) = result and
- this.(PythonFunctionObjectInternal).getScope().getArg(n+offset).getName() = name
+ this.(PythonFunctionObjectInternal).getScope().getArg(n + offset).getName() = name
)
or
call.getArgByName(name) = result and
exists(this.(PythonFunctionObjectInternal).getScope().getArgByName(name))
or
called instanceof BoundMethodObjectInternal and
- offset = 1 and name = "self" and result = call.getFunction().(AttrNode).getObject()
+ offset = 1 and
+ name = "self" and
+ result = call.getFunction().(AttrNode).getObject()
)
}
-
}
-/** Class representing classes in the Python program, both Python and built-in.
+/**
+ * Class representing classes in the Python program, both Python and built-in.
*/
class ClassValue extends Value {
-
- ClassValue() {
- this.(ObjectInternal).isClass() = true
- }
+ ClassValue() { this.(ObjectInternal).isClass() = true }
/** Gets an improper super type of this class. */
- ClassValue getASuperType() {
- result = this.getABaseType*()
- }
+ ClassValue getASuperType() { result = this.getABaseType*() }
- /** Looks up the attribute `name` on this class.
+ /**
+ * Looks up the attribute `name` on this class.
* Note that this may be different from `this.attr(name)`.
* For example given the class:
* ```class C:
@@ -444,15 +415,11 @@ class ClassValue extends Value {
* ```
* `this.lookup("f")` is equivalent to `C.__dict__['f']`, which is the class-method
* whereas
- * `this.attr("f") is equivalent to `C.f`, which is a bound-method.
+ * `this.attr("f")` is equivalent to `C.f`, which is a bound-method.
*/
- Value lookup(string name) {
- this.(ClassObjectInternal).lookup(name, result, _)
- }
+ Value lookup(string name) { this.(ClassObjectInternal).lookup(name, result, _) }
- predicate isCallable() {
- this.(ClassObjectInternal).lookup("__call__", _, _)
- }
+ predicate isCallable() { this.(ClassObjectInternal).lookup("__call__", _, _) }
/** Holds if this class is an iterable. */
predicate isIterable() {
@@ -462,17 +429,17 @@ class ClassValue extends Value {
or
this.hasAttribute("__getitem__")
}
-
- /** Holds if this class is a container(). That is, does it have a __getitem__ method.*/
- predicate isContainer() {
- exists(this.lookup("__getitem__"))
- }
-
+
+ /** Holds if this class is a container(). That is, does it have a __getitem__ method. */
+ predicate isContainer() { exists(this.lookup("__getitem__")) }
+
/** Holds if this class is probably a sequence. */
predicate isSequence() {
- /* To determine whether something is a sequence or a mapping is not entirely clear,
+ /*
+ * To determine whether something is a sequence or a mapping is not entirely clear,
* so we need to guess a bit.
*/
+
this.getASuperType() = ClassValue::tuple()
or
this.getASuperType() = ClassValue::list()
@@ -494,18 +461,15 @@ class ClassValue extends Value {
this.hasAttribute("__reversed__")
)
}
-
+
/** Holds if this class is a mapping. */
predicate isMapping() {
- this.hasAttribute("__getitem__")
- and
+ this.hasAttribute("__getitem__") and
not this.isSequence()
}
/** Holds if this class is a descriptor. */
- predicate isDescriptorType() {
- this.hasAttribute("__get__")
- }
+ predicate isDescriptorType() { this.hasAttribute("__get__") }
/** Holds if this class is a context manager. */
predicate isContextManager() {
@@ -513,7 +477,8 @@ class ClassValue extends Value {
this.hasAttribute("__exit__")
}
- /** Gets the qualified name for this class.
+ /**
+ * Gets the qualified name for this class.
* Should return the same name as the `__qualname__` attribute on classes in Python 3.
*/
string getQualifiedName() {
@@ -523,62 +488,52 @@ class ClassValue extends Value {
}
/** Gets the MRO for this class */
- MRO getMro() {
- result = Types::getMro(this)
- }
+ MRO getMro() { result = Types::getMro(this) }
- predicate failedInference(string reason) {
- Types::failedInference(this, reason)
- }
+ predicate failedInference(string reason) { Types::failedInference(this, reason) }
/** Gets the nth immediate base type of this class. */
- ClassValue getBaseType(int n) {
- result = Types::getBase(this, n)
- }
+ ClassValue getBaseType(int n) { result = Types::getBase(this, n) }
/** Gets an immediate base type of this class. */
- ClassValue getABaseType() {
- result = Types::getBase(this, _)
- }
+ ClassValue getABaseType() { result = Types::getBase(this, _) }
- /** Holds if this class is a new style class.
- A new style class is one that implicitly or explicitly inherits from `object`. */
- predicate isNewStyle() {
- Types::isNewStyle(this)
- }
+ /**
+ * Holds if this class is a new style class.
+ * A new style class is one that implicitly or explicitly inherits from `object`.
+ */
+ predicate isNewStyle() { Types::isNewStyle(this) }
- /** Holds if this class is an old style class.
- An old style class is one that does not inherit from `object`. */
- predicate isOldStyle() {
- Types::isOldStyle(this)
- }
+ /**
+ * Holds if this class is an old style class.
+ * An old style class is one that does not inherit from `object`.
+ */
+ predicate isOldStyle() { Types::isOldStyle(this) }
/** Gets the scope associated with this class, if it is not a builtin class */
- ClassScope getScope() {
- result = this.(PythonClassObjectInternal).getScope()
- }
+ ClassScope getScope() { result = this.(PythonClassObjectInternal).getScope() }
/** Gets the attribute declared in this class */
- Value declaredAttribute(string name) {
- Types::declaredAttribute(this, name, result, _)
- }
+ Value declaredAttribute(string name) { Types::declaredAttribute(this, name, result, _) }
- /** Holds if this class has the attribute `name`, including
+ /**
+ * Holds if this class has the attribute `name`, including
* attributes declared by super classes.
*/
- predicate hasAttribute(string name) {
- this.getMro().declares(name)
- }
+ predicate hasAttribute(string name) { this.getMro().declares(name) }
- /** Holds if this class declares the attribute `name`,
+ /**
+ * Holds if this class declares the attribute `name`,
* *not* including attributes declared by super classes.
*/
predicate declaresAttribute(string name) {
this.(ClassObjectInternal).getClassDeclaration().declaresAttribute(name)
}
- /** Whether this class is a legal exception class.
- * What constitutes a legal exception class differs between major versions */
+ /**
+ * Whether this class is a legal exception class.
+ * What constitutes a legal exception class differs between major versions
+ */
predicate isLegalExceptionType() {
not this.isNewStyle()
or
@@ -586,30 +541,27 @@ class ClassValue extends Value {
or
major_version() = 2 and this = ClassValue::tuple()
}
-
}
-
-/** Class representing functions in the Python program, both Python and built-in.
+/**
+ * Class representing functions in the Python program, both Python and built-in.
* Note that this does not include other callables such as bound-methods.
*/
abstract class FunctionValue extends CallableValue {
-
abstract string getQualifiedName();
+ /** Gets a longer, more descriptive version of toString() */
+ abstract string descriptiveString();
+
/** Gets the minimum number of parameters that can be correctly passed to this function */
abstract int minParameters();
/** Gets the maximum number of parameters that can be correctly passed to this function */
abstract int maxParameters();
- predicate isOverridingMethod() {
- exists(Value f | this.overrides(f))
- }
+ predicate isOverridingMethod() { exists(Value f | this.overrides(f)) }
- predicate isOverriddenMethod() {
- exists(Value f | f.overrides(this))
- }
+ predicate isOverriddenMethod() { exists(Value f | f.overrides(this)) }
/** Whether `name` is a legal argument name for this function */
bindingset[name]
@@ -621,24 +573,40 @@ abstract class FunctionValue extends CallableValue {
this.getScope().hasKwArg()
}
- /** Whether this is a "normal" method, that is, it is exists as a class attribute
- * which is not a lambda and not the __new__ method. */
+ /**
+ * Whether this is a "normal" method, that is, it is exists as a class attribute
+ * which is not a lambda and not the __new__ method.
+ */
predicate isNormalMethod() {
exists(ClassValue cls, string name |
cls.declaredAttribute(name) = this and
name != "__new__" and
- exists(Expr expr, AstNode origin | expr.pointsTo(this, origin) |
- not origin instanceof Lambda
- )
+ exists(Expr expr, AstNode origin | expr.pointsTo(this, origin) | not origin instanceof Lambda)
)
}
+
+ /** Gets a class that may be raised by this function */
+ abstract ClassValue getARaisedType();
+
+ /** Gets a class that this function may return */
+ ClassValue getAnInferredReturnType() {
+ result = TBuiltinClassObject(this.(BuiltinFunctionObjectInternal).getReturnType())
+ or
+ result = TBuiltinClassObject(this.(BuiltinMethodObjectInternal).getReturnType())
+ }
}
/** Class representing Python functions */
class PythonFunctionValue extends FunctionValue {
+ PythonFunctionValue() { this instanceof PythonFunctionObjectInternal }
- PythonFunctionValue() {
- this instanceof PythonFunctionObjectInternal
+ override string descriptiveString() {
+ if this.getScope().isMethod()
+ then
+ exists(Class cls | this.getScope().getScope() = cls |
+ result = "method " + this.getQualifiedName()
+ )
+ else result = "function " + this.getQualifiedName()
}
override string getQualifiedName() {
@@ -655,10 +623,9 @@ class PythonFunctionValue extends FunctionValue {
override int maxParameters() {
exists(Function f |
f = this.getScope() and
- if exists(f.getVararg()) then
- result = 2147483647 // INT_MAX
- else
- result = count(f.getAnArg())
+ if exists(f.getVararg())
+ then result = 2147483647 // INT_MAX
+ else result = count(f.getAnArg())
)
}
@@ -667,18 +634,19 @@ class PythonFunctionValue extends FunctionValue {
result = this.getScope().getAReturnValueFlowNode()
}
+ override ClassValue getARaisedType() {
+ scope_raises(result, this.getScope())
+ }
+
}
/** Class representing builtin functions, such as `len` or `print` */
class BuiltinFunctionValue extends FunctionValue {
+ BuiltinFunctionValue() { this instanceof BuiltinFunctionObjectInternal }
- BuiltinFunctionValue() {
- this instanceof BuiltinFunctionObjectInternal
- }
+ override string getQualifiedName() { result = this.(BuiltinFunctionObjectInternal).getName() }
- override string getQualifiedName() {
- result = this.(BuiltinFunctionObjectInternal).getName()
- }
+ override string descriptiveString() { result = "builtin-function " + this.getName() }
override int minParameters() {
none()
@@ -687,14 +655,16 @@ class BuiltinFunctionValue extends FunctionValue {
override int maxParameters() {
none()
}
+
+ override ClassValue getARaisedType() {
+ /* Information is unavailable for C code in general */
+ none()
+ }
}
/** Class representing builtin methods, such as `list.append` or `set.add` */
class BuiltinMethodValue extends FunctionValue {
-
- BuiltinMethodValue() {
- this instanceof BuiltinMethodObjectInternal
- }
+ BuiltinMethodValue() { this instanceof BuiltinMethodObjectInternal }
override string getQualifiedName() {
exists(Builtin cls |
@@ -704,6 +674,8 @@ class BuiltinMethodValue extends FunctionValue {
)
}
+ override string descriptiveString() { result = "builtin-method " + this.getQualifiedName() }
+
override int minParameters() {
none()
}
@@ -712,38 +684,33 @@ class BuiltinMethodValue extends FunctionValue {
none()
}
+ override ClassValue getARaisedType() {
+ /* Information is unavailable for C code in general */
+ none()
+ }
+
}
-/** A class representing sequence objects with a length and tracked items.
+/**
+ * A class representing sequence objects with a length and tracked items.
*/
class SequenceValue extends Value {
+ SequenceValue() { this instanceof SequenceObjectInternal }
- SequenceValue() {
- this instanceof SequenceObjectInternal
- }
-
- Value getItem(int n) {
- result = this.(SequenceObjectInternal).getItem(n)
- }
-
- int length() {
- result = this.(SequenceObjectInternal).length()
- }
+ Value getItem(int n) { result = this.(SequenceObjectInternal).getItem(n) }
+ int length() { result = this.(SequenceObjectInternal).length() }
}
/** A class representing tuple objects */
class TupleValue extends SequenceValue {
-
- TupleValue() {
- this instanceof TupleObjectInternal
- }
-
+ TupleValue() { this instanceof TupleObjectInternal }
}
-/** A class representing strings, either present in the source as a literal, or
-in a builtin as a value. */
-
+/**
+ * A class representing strings, either present in the source as a literal, or
+ * in a builtin as a value.
+ */
class StringValue extends Value {
StringValue() {
this instanceof BytesObjectInternal or
@@ -757,8 +724,9 @@ class StringValue extends Value {
}
}
-/** A class representing numbers (ints and floats), either present in the source as a literal,
- * or in a builtin as a value.
+/**
+ * A class representing numbers (ints and floats), either present in the source as a literal,
+ * or in a builtin as a value.
*/
class NumericValue extends Value {
NumericValue() {
@@ -767,102 +735,66 @@ class NumericValue extends Value {
}
/** Gets the integer-value if it is a constant integer, and it fits in a QL int */
- int getIntValue() {
- result = this.(IntObjectInternal).intValue()
- }
+ int getIntValue() { result = this.(IntObjectInternal).intValue() }
/** Gets the float-value if it is a constant float */
- int getFloatValue() {
- result = this.(FloatObjectInternal).floatValue()
- }
+ int getFloatValue() { result = this.(FloatObjectInternal).floatValue() }
}
-/** A Python property:
- * @property
- * def f():
+/**
+ * A Python property:
+ *
+ * @property def f():
* ....
*
* https://docs.python.org/3/howto/descriptor.html#properties
* https://docs.python.org/3/library/functions.html#property
*/
class PropertyValue extends Value {
+ PropertyValue() { this instanceof PropertyInternal }
- PropertyValue() {
- this instanceof PropertyInternal
- }
+ CallableValue getGetter() { result = this.(PropertyInternal).getGetter() }
- CallableValue getGetter(){
- result = this.(PropertyInternal).getGetter()
- }
-
- CallableValue getSetter(){
- result = this.(PropertyInternal).getSetter()
- }
-
- CallableValue getDeleter(){
- result = this.(PropertyInternal).getDeleter()
- }
+ CallableValue getSetter() { result = this.(PropertyInternal).getSetter() }
+ CallableValue getDeleter() { result = this.(PropertyInternal).getDeleter() }
}
/** A method-resolution-order sequence of classes */
class MRO extends TClassList {
-
- string toString() {
- result = this.(ClassList).toString()
- }
+ string toString() { result = this.(ClassList).toString() }
/** Gets the `n`th class in this MRO */
- ClassValue getItem(int n) {
- result = this.(ClassList).getItem(n)
- }
+ ClassValue getItem(int n) { result = this.(ClassList).getItem(n) }
/** Holds if any class in this MRO declares the attribute `name` */
- predicate declares(string name) {
- this.(ClassList).declares(name)
- }
+ predicate declares(string name) { this.(ClassList).declares(name) }
/** Gets the length of this MRO */
- int length() {
- result = this.(ClassList).length()
- }
+ int length() { result = this.(ClassList).length() }
/** Holds if this MRO contains `cls` */
- predicate contains(ClassValue cls) {
- this.(ClassList).contains(cls)
- }
+ predicate contains(ClassValue cls) { this.(ClassList).contains(cls) }
/** Gets the value from scanning for the attribute `name` in this MRO. */
- Value lookup(string name) {
- this.(ClassList).lookup(name, result, _)
- }
+ Value lookup(string name) { this.(ClassList).lookup(name, result, _) }
- /** Gets the MRO formed by removing all classes before `cls`
+ /**
+ * Gets the MRO formed by removing all classes before `cls`
* from this MRO.
*/
- MRO startingAt(ClassValue cls) {
- result = this.(ClassList).startingAt(cls)
- }
-
+ MRO startingAt(ClassValue cls) { result = this.(ClassList).startingAt(cls) }
}
-
module ClassValue {
-
/** Get the `ClassValue` for the `bool` class. */
- ClassValue bool() {
- result = TBuiltinClassObject(Builtin::special("bool"))
- }
+ ClassValue bool() { result = TBuiltinClassObject(Builtin::special("bool")) }
/** Get the `ClassValue` for the `tuple` class. */
- ClassValue tuple() {
- result = TBuiltinClassObject(Builtin::special("tuple"))
- }
+ ClassValue tuple() { result = TBuiltinClassObject(Builtin::special("tuple")) }
/** Get the `ClassValue` for the `list` class. */
- ClassValue list() {
- result = TBuiltinClassObject(Builtin::special("list"))
- }
+ ClassValue list() { result = TBuiltinClassObject(Builtin::special("list")) }
/** Get the `ClassValue` for `xrange` (Python 2), or `range` (only Python 3) */
ClassValue range() {
@@ -872,115 +804,74 @@ module ClassValue {
}
/** Get the `ClassValue` for the `dict` class. */
- ClassValue dict() {
- result = TBuiltinClassObject(Builtin::special("dict"))
- }
+ ClassValue dict() { result = TBuiltinClassObject(Builtin::special("dict")) }
/** Get the `ClassValue` for the `set` class. */
- ClassValue set() {
- result = TBuiltinClassObject(Builtin::special("set"))
- }
+ ClassValue set() { result = TBuiltinClassObject(Builtin::special("set")) }
/** Get the `ClassValue` for the `object` class. */
- ClassValue object() {
- result = TBuiltinClassObject(Builtin::special("object"))
- }
+ ClassValue object() { result = TBuiltinClassObject(Builtin::special("object")) }
/** Get the `ClassValue` for the `int` class. */
- ClassValue int_() {
- result = TBuiltinClassObject(Builtin::special("int"))
- }
+ ClassValue int_() { result = TBuiltinClassObject(Builtin::special("int")) }
/** Get the `ClassValue` for the `long` class. */
- ClassValue long() {
- result = TBuiltinClassObject(Builtin::special("long"))
- }
+ ClassValue long() { result = TBuiltinClassObject(Builtin::special("long")) }
/** Get the `ClassValue` for the `float` class. */
- ClassValue float_() {
- result = TBuiltinClassObject(Builtin::special("float"))
- }
+ ClassValue float_() { result = TBuiltinClassObject(Builtin::special("float")) }
/** Get the `ClassValue` for the `complex` class. */
- ClassValue complex() {
- result = TBuiltinClassObject(Builtin::special("complex"))
- }
-
+ ClassValue complex() { result = TBuiltinClassObject(Builtin::special("complex")) }
+
/** Get the `ClassValue` for the `bytes` class (also called `str` in Python 2). */
- ClassValue bytes() {
- result = TBuiltinClassObject(Builtin::special("bytes"))
- }
+ ClassValue bytes() { result = TBuiltinClassObject(Builtin::special("bytes")) }
- /** Get the `ClassValue` for the class of unicode strings.
- * `str` in Python 3 and `unicode` in Python 2. */
- ClassValue unicode() {
- result = TBuiltinClassObject(Builtin::special("unicode"))
- }
+ /**
+ * Get the `ClassValue` for the class of unicode strings.
+ * `str` in Python 3 and `unicode` in Python 2.
+ */
+ ClassValue unicode() { result = TBuiltinClassObject(Builtin::special("unicode")) }
- /** Get the `ClassValue` for the `str` class. This is `bytes` in Python 2,
- and `str` in Python 3. */
- ClassValue str() {
- if major_version() = 2 then
- result = bytes()
- else
- result = unicode()
- }
+ /**
+ * Get the `ClassValue` for the `str` class. This is `bytes` in Python 2,
+ * and `str` in Python 3.
+ */
+ ClassValue str() { if major_version() = 2 then result = bytes() else result = unicode() }
/** Get the `ClassValue` for the `property` class. */
- ClassValue property() {
- result = TBuiltinClassObject(Builtin::special("property"))
- }
+ ClassValue property() { result = TBuiltinClassObject(Builtin::special("property")) }
/** Get the `ClassValue` for the class of Python functions. */
- ClassValue functionType() {
- result = TBuiltinClassObject(Builtin::special("FunctionType"))
- }
+ ClassValue functionType() { result = TBuiltinClassObject(Builtin::special("FunctionType")) }
/** Get the `ClassValue` for the class of builtin functions. */
- ClassValue builtinFunction() {
- result = Value::named("len").getClass()
- }
+ ClassValue builtinFunction() { result = Value::named("len").getClass() }
/** Get the `ClassValue` for the `generatorType` class. */
- ClassValue generator() {
- result = TBuiltinClassObject(Builtin::special("generator"))
- }
+ ClassValue generator() { result = TBuiltinClassObject(Builtin::special("generator")) }
/** Get the `ClassValue` for the `type` class. */
- ClassValue type() {
- result = TType()
- }
+ ClassValue type() { result = TType() }
/** Get the `ClassValue` for `ClassType`. */
- ClassValue classType() {
- result = TBuiltinClassObject(Builtin::special("ClassType"))
- }
+ ClassValue classType() { result = TBuiltinClassObject(Builtin::special("ClassType")) }
/** Get the `ClassValue` for `InstanceType`. */
- ClassValue instanceType() {
- result = TBuiltinClassObject(Builtin::special("InstanceType"))
- }
+ ClassValue instanceType() { result = TBuiltinClassObject(Builtin::special("InstanceType")) }
/** Get the `ClassValue` for `super`. */
- ClassValue super_() {
- result = TBuiltinClassObject(Builtin::special("super"))
- }
+ ClassValue super_() { result = TBuiltinClassObject(Builtin::special("super")) }
/** Get the `ClassValue` for the `classmethod` class. */
- ClassValue classmethod() {
- result = TBuiltinClassObject(Builtin::special("ClassMethod"))
- }
+ ClassValue classmethod() { result = TBuiltinClassObject(Builtin::special("ClassMethod")) }
/** Get the `ClassValue` for the `staticmethod` class. */
- ClassValue staticmethod() {
- result = TBuiltinClassObject(Builtin::special("StaticMethod"))
- }
+ ClassValue staticmethod() { result = TBuiltinClassObject(Builtin::special("StaticMethod")) }
/** Get the `ClassValue` for the `MethodType` class. */
- pragma [noinline]
- ClassValue methodType() {
- result = TBuiltinClassObject(Builtin::special("MethodType"))
- }
+ pragma[noinline]
+ ClassValue methodType() { result = TBuiltinClassObject(Builtin::special("MethodType")) }
/** Get the `ClassValue` for the `MethodDescriptorType` class. */
ClassValue methodDescriptorType() {
@@ -993,59 +884,42 @@ module ClassValue {
}
/** Get the `ClassValue` for the `StopIteration` class. */
- ClassValue stopIteration() {
- result = TBuiltinClassObject(Builtin::builtin("StopIteration"))
- }
+ ClassValue stopIteration() { result = TBuiltinClassObject(Builtin::builtin("StopIteration")) }
/** Get the `ClassValue` for the class of modules. */
- ClassValue module_() {
- result = TBuiltinClassObject(Builtin::special("ModuleType"))
- }
+ ClassValue module_() { result = TBuiltinClassObject(Builtin::special("ModuleType")) }
/** Get the `ClassValue` for the `Exception` class. */
- ClassValue exception() {
- result = TBuiltinClassObject(Builtin::special("Exception"))
- }
+ ClassValue exception() { result = TBuiltinClassObject(Builtin::special("Exception")) }
/** Get the `ClassValue` for the `BaseException` class. */
- ClassValue baseException() {
- result = TBuiltinClassObject(Builtin::special("BaseException"))
- }
+ ClassValue baseException() { result = TBuiltinClassObject(Builtin::special("BaseException")) }
/** Get the `ClassValue` for the `NoneType` class. */
- ClassValue nonetype() {
- result = TBuiltinClassObject(Builtin::special("NoneType"))
- }
+ ClassValue nonetype() { result = TBuiltinClassObject(Builtin::special("NoneType")) }
/** Get the `ClassValue` for the `TypeError` class */
- ClassValue typeError() {
- result = TBuiltinClassObject(Builtin::special("TypeError"))
- }
+ ClassValue typeError() { result = TBuiltinClassObject(Builtin::special("TypeError")) }
/** Get the `ClassValue` for the `NameError` class. */
- ClassValue nameError() {
- result = TBuiltinClassObject(Builtin::builtin("NameError"))
- }
+ ClassValue nameError() { result = TBuiltinClassObject(Builtin::builtin("NameError")) }
/** Get the `ClassValue` for the `AttributeError` class. */
- ClassValue attributeError() {
- result = TBuiltinClassObject(Builtin::builtin("AttributeError"))
- }
+ ClassValue attributeError() { result = TBuiltinClassObject(Builtin::builtin("AttributeError")) }
/** Get the `ClassValue` for the `KeyError` class. */
- ClassValue keyError() {
- result = TBuiltinClassObject(Builtin::builtin("KeyError"))
- }
+ ClassValue keyError() { result = TBuiltinClassObject(Builtin::builtin("KeyError")) }
/** Get the `ClassValue` for the `LookupError` class. */
- ClassValue lookupError() {
- result = TBuiltinClassObject(Builtin::builtin("LookupError"))
- }
+ ClassValue lookupError() { result = TBuiltinClassObject(Builtin::builtin("LookupError")) }
- /** Get the `ClassValue` for the `IOError` class. */
- ClassValue ioError() {
- result = TBuiltinClassObject(Builtin::builtin("IOError"))
+ /** Get the `ClassValue` for the `IndexError` class. */
+ ClassValue indexError() {
+ result = TBuiltinClassObject(Builtin::builtin("IndexError"))
}
+
+ /** Get the `ClassValue` for the `IOError` class. */
+ ClassValue ioError() { result = TBuiltinClassObject(Builtin::builtin("IOError")) }
/** Get the `ClassValue` for the `NotImplementedError` class. */
ClassValue notImplementedError() {
@@ -1053,9 +927,7 @@ module ClassValue {
}
/** Get the `ClassValue` for the `ImportError` class. */
- ClassValue importError() {
- result = TBuiltinClassObject(Builtin::builtin("ImportError"))
- }
+ ClassValue importError() { result = TBuiltinClassObject(Builtin::builtin("ImportError")) }
/** Get the `ClassValue` for the `UnicodeEncodeError` class. */
ClassValue unicodeEncodeError() {
@@ -1067,4 +939,9 @@ module ClassValue {
result = TBuiltinClassObject(Builtin::builtin("UnicodeDecodeError"))
}
+ /** Get the `ClassValue` for the `SystemExit` class. */
+ ClassValue systemExit() {
+ result = TBuiltinClassObject(Builtin::builtin("SystemExit"))
+ }
+
}
From 161613f59efe6b12ed1a6d35cea9545e90a6b949 Mon Sep 17 00:00:00 2001
From: Rebecca Valentine
Date: Thu, 2 Apr 2020 12:17:14 -0700
Subject: [PATCH 0046/1298] Python: ObjectAPI to ValueAPI:
WrongNumberArgumentsInCall: Adds new version of Exceptions.qll
---
.../ql/src/semmle/python/types/Exceptions.qll | 388 ++++++++++++------
1 file changed, 258 insertions(+), 130 deletions(-)
diff --git a/python/ql/src/semmle/python/types/Exceptions.qll b/python/ql/src/semmle/python/types/Exceptions.qll
index 2ed034da77b..9de373f73d4 100644
--- a/python/ql/src/semmle/python/types/Exceptions.qll
+++ b/python/ql/src/semmle/python/types/Exceptions.qll
@@ -1,6 +1,6 @@
/**
* Analysis of exception raising and handling.
- *
+ *
* In order to make this useful we make a number of assumptions. These are:
* 1. Typing errors (TypeError, NameError, AttributeError) are assumed to occur only if:
* a) Explicitly raised, e.g. raise TypeError()
@@ -15,7 +15,6 @@ import python
/** Subset of ControlFlowNodes which might raise an exception */
class RaisingNode extends ControlFlowNode {
-
RaisingNode() {
exists(this.getAnExceptionalSuccessor())
or
@@ -24,64 +23,104 @@ class RaisingNode extends ControlFlowNode {
/** Gets the CFG node for the exception, if and only if this RaisingNode is an explicit raise */
ControlFlowNode getExceptionNode() {
- exists(Raise r |
- r = this.getNode() and result.getNode() = r.getRaised() and
+ exists(Raise r |
+ r = this.getNode() and
+ result.getNode() = r.getRaised() and
result.getBasicBlock().dominates(this.getBasicBlock())
)
}
- private predicate quits() {
- this.(CallNode).getFunction().refersTo(Object::quitter(_))
+ private predicate quits() { this.(CallNode).getFunction().refersTo(Object::quitter(_)) }
+
+ /**
+ * Gets the type of an exception that may be raised
+ * at this control flow node
+ */
+ ClassObject getARaisedType_objectapi() {
+ result = this.localRaisedType_objectapi()
+ or
+ exists(FunctionObject func | this = func.getACall() | result = func.getARaisedType())
+ or
+ result = systemExitRaise_objectapi()
}
- /** Gets the type of an exception that may be raised
- at this control flow node */
- ClassObject getARaisedType() {
+ /**
+ * Gets the type of an exception that may be raised
+ * at this control flow node
+ */
+ ClassValue getARaisedType() {
result = this.localRaisedType()
or
- exists(FunctionObject func |
- this = func.getACall() |
- result = func.getARaisedType()
- )
+ exists(FunctionValue func | this = func.getACall() | result = func.getARaisedType())
or
result = systemExitRaise()
}
pragma[noinline]
- private ClassObject systemExitRaise() {
+ private ClassObject systemExitRaise_objectapi() {
this.quits() and result = Object::builtin("SystemExit")
}
- pragma [noinline, nomagic]
- private ClassObject localRaisedType() {
- result.isSubclassOf(theBaseExceptionType())
- and
+ pragma[noinline]
+ private ClassValue systemExitRaise() { this.quits() and result = ClassValue::systemExit() }
+
+ pragma[noinline, nomagic]
+ private ClassObject localRaisedType_objectapi() {
+ result.isSubclassOf(theBaseExceptionType()) and
(
- exists(ControlFlowNode ex |
- ex = this.getExceptionNode() and
- (ex.refersTo(result) or ex.refersTo(_, result, _))
- )
- or
- this.getNode() instanceof ImportExpr and result = Object::builtin("ImportError")
- or
- this.getNode() instanceof Print and result = theIOErrorType()
- or
- exists(ExceptFlowNode except |
- except = this.getAnExceptionalSuccessor() and
- except.handles(result) and
- result = this.innateException()
- )
- or
- not exists(ExceptFlowNode except | except = this.getAnExceptionalSuccessor())
- and
- sequence_or_mapping(this) and result = theLookupErrorType()
- or
- this.read_write_call() and result = theIOErrorType()
+ exists(ControlFlowNode ex |
+ ex = this.getExceptionNode() and
+ (ex.refersTo(result) or ex.refersTo(_, result, _))
+ )
+ or
+ this.getNode() instanceof ImportExpr and result = Object::builtin("ImportError")
+ or
+ this.getNode() instanceof Print and result = theIOErrorType()
+ or
+ exists(ExceptFlowNode except |
+ except = this.getAnExceptionalSuccessor() and
+ except.handles_objectapi(result) and
+ result = this.innateException_objectapi()
+ )
+ or
+ not exists(ExceptFlowNode except | except = this.getAnExceptionalSuccessor()) and
+ sequence_or_mapping(this) and
+ result = theLookupErrorType()
+ or
+ this.read_write_call() and result = theIOErrorType()
)
}
- pragma [noinline]
- ClassObject innateException() {
+ pragma[noinline, nomagic]
+ private ClassValue localRaisedType() {
+ result.getASuperType() = ClassValue::baseException() and
+ (
+ exists(ControlFlowNode ex |
+ ex = this.getExceptionNode() and
+ (ex.pointsTo(result) or ex.pointsTo(_, result, _))
+ )
+ or
+ this.getNode() instanceof ImportExpr and result = ClassValue::importError()
+ or
+ this.getNode() instanceof Print and result = ClassValue::ioError()
+ or
+ exists(ExceptFlowNode except |
+ except = this.getAnExceptionalSuccessor() and
+ except.handles(result) and
+ result = this.innateException()
+ )
+ or
+ not exists(ExceptFlowNode except | except = this.getAnExceptionalSuccessor()) and
+ sequence_or_mapping(this) and
+ result = ClassValue::lookupError()
+ or
+ this.read_write_call() and result = ClassValue::ioError()
+ )
+ }
+
+ /** Holds if this is an innate exception (AttributeError, NameError, IndexError, or KeyError). */
+ pragma[noinline]
+ ClassObject innateException_objectapi() {
this.getNode() instanceof Attribute and result = theAttributeErrorType()
or
this.getNode() instanceof Name and result = theNameErrorType()
@@ -91,38 +130,48 @@ class RaisingNode extends ControlFlowNode {
this.getNode() instanceof Subscript and result = theKeyErrorType()
}
- /** Whether this control flow node raises an exception,
- * but the type of the exception it raises cannot be inferred. */
+ /** Holds if this is an innate exception (AttributeError, NameError, IndexError, or KeyError). */
+ pragma[noinline]
+ ClassValue innateException() {
+ this.getNode() instanceof Attribute and result = ClassValue::attributeError()
+ or
+ this.getNode() instanceof Name and result = ClassValue::nameError()
+ or
+ this.getNode() instanceof Subscript and result = ClassValue::indexError()
+ or
+ this.getNode() instanceof Subscript and result = ClassValue::keyError()
+ }
+
+ /**
+ * Whether this control flow node raises an exception,
+ * but the type of the exception it raises cannot be inferred.
+ */
predicate raisesUnknownType() {
/* read/write calls are assumed to raise IOError (OSError for Py3) */
- not this.read_write_call()
- and
+ not this.read_write_call() and
(
- /* Call to an unknown object */
- this.getNode() instanceof Call and not exists(FunctionObject func | this = func.getACall())
- and not exists(ClassObject known | this.(CallNode).getFunction().refersTo(known))
- or
- this.getNode() instanceof Exec
- or
- /* Call to a function raising an unknown type */
- exists(FunctionObject func |
- this = func.getACall() |
- func.raisesUnknownType()
- )
+ /* Call to an unknown object */
+ this.getNode() instanceof Call and
+ not exists(FunctionObject func | this = func.getACall()) and
+ not exists(ClassObject known | this.(CallNode).getFunction().refersTo(known))
+ or
+ this.getNode() instanceof Exec
+ or
+ /* Call to a function raising an unknown type */
+ exists(FunctionObject func | this = func.getACall() | func.raisesUnknownType())
)
}
private predicate read_write_call() {
exists(string mname | mname = this.(CallNode).getFunction().(AttrNode).getName() |
- mname = "read" or mname = "write"
+ mname = "read" or mname = "write"
)
}
- /** Whether (as inferred by type inference) it is highly unlikely (or impossible) for control to flow from this to succ.
- */
+ /** Whether (as inferred by type inference) it is highly unlikely (or impossible) for control to flow from this to succ. */
predicate unlikelySuccessor(ControlFlowNode succ) {
succ = this.getAnExceptionalSuccessor() and
- not this.viableExceptionEdge(succ, _) and
+ not this.viableExceptionEdge_objectapi(succ, _) and
not this.raisesUnknownType()
or
exists(FunctionObject func |
@@ -140,84 +189,159 @@ class RaisingNode extends ControlFlowNode {
}
/** Whether it is considered plausible that 'raised' can be raised across the edge this-succ */
- predicate viableExceptionEdge(ControlFlowNode succ, ClassObject raised) {
+ predicate viableExceptionEdge_objectapi(ControlFlowNode succ, ClassObject raised) {
raised.isLegalExceptionType() and
- raised = this.getARaisedType() and
+ raised = this.getARaisedType_objectapi() and
succ = this.getAnExceptionalSuccessor() and
- (
+ (
/* An 'except' that handles raised and there is no more previous handler */
- ((ExceptFlowNode)succ).handles(raised) and
- not exists(ExceptFlowNode other, StmtList s, int i, int j |
- not other = succ and other.handles(raised) and
- s.getItem(i) = succ.getNode() and s.getItem(j) = other.getNode()
- |
+ succ.(ExceptFlowNode).handles_objectapi(raised) and
+ not exists(ExceptFlowNode other, StmtList s, int i, int j |
+ not other = succ and
+ other.handles_objectapi(raised) and
+ s.getItem(i) = succ.getNode() and
+ s.getItem(j) = other.getNode()
+ |
j < i
)
or
/* Any successor that is not an 'except', provided that 'raised' is not handled by a different successor. */
- (not ((ExceptFlowNode)this.getAnExceptionalSuccessor()).handles(raised) and
- not succ instanceof ExceptFlowNode)
+ not this.getAnExceptionalSuccessor().(ExceptFlowNode).handles_objectapi(raised) and
+ not succ instanceof ExceptFlowNode
)
}
- /** Whether this exceptional exit is viable. That is, is it
+ /** Whether it is considered plausible that 'raised' can be raised across the edge this-succ */
+ predicate viableExceptionEdge(ControlFlowNode succ, ClassValue raised) {
+ raised.isLegalExceptionType() and
+ raised = this.getARaisedType() and
+ succ = this.getAnExceptionalSuccessor() and
+ (
+ /* An 'except' that handles raised and there is no more previous handler */
+ succ.(ExceptFlowNode).handles(raised) and
+ not exists(ExceptFlowNode other, StmtList s, int i, int j |
+ not other = succ and
+ other.handles(raised) and
+ s.getItem(i) = succ.getNode() and
+ s.getItem(j) = other.getNode()
+ |
+ j < i
+ )
+ or
+ /* Any successor that is not an 'except', provided that 'raised' is not handled by a different successor. */
+ not this.getAnExceptionalSuccessor().(ExceptFlowNode).handles(raised) and
+ not succ instanceof ExceptFlowNode
+ )
+ }
+
+ /**
+ * Whether this exceptional exit is viable. That is, is it
* plausible that the scope `s` can be exited with exception `raised`
* at this point.
*/
- predicate viableExceptionalExit(Scope s, ClassObject raised) {
+ predicate viableExceptionalExit_objectapi(Scope s, ClassObject raised) {
+ raised.isLegalExceptionType() and
+ raised = this.getARaisedType_objectapi() and
+ this.isExceptionalExit(s) and
+ not this.getAnExceptionalSuccessor().(ExceptFlowNode).handles_objectapi(raised)
+ }
+
+ /**
+ * Whether this exceptional exit is viable. That is, is it
+ * plausible that the scope `s` can be exited with exception `raised`
+ * at this point.
+ */
+ predicate viableExceptionalExit(Scope s, ClassValue raised) {
raised.isLegalExceptionType() and
raised = this.getARaisedType() and
this.isExceptionalExit(s) and
- not ((ExceptFlowNode)this.getAnExceptionalSuccessor()).handles(raised)
+ not this.getAnExceptionalSuccessor().(ExceptFlowNode).handles(raised)
}
-
}
/** Is this a sequence or mapping subscript x[i]? */
-private predicate sequence_or_mapping(RaisingNode r) {
- r.getNode() instanceof Subscript
+private predicate sequence_or_mapping(RaisingNode r) { r.getNode() instanceof Subscript }
+
+private predicate current_exception_objectapi(ClassObject ex, BasicBlock b) {
+ exists(RaisingNode r |
+ r.viableExceptionEdge_objectapi(b.getNode(0), ex) and not b.getNode(0) instanceof ExceptFlowNode
+ )
+ or
+ exists(BasicBlock prev |
+ current_exception_objectapi(ex, prev) and
+ exists(ControlFlowNode pred, ControlFlowNode succ |
+ pred = prev.getLastNode() and succ = b.getNode(0)
+ |
+ pred.getASuccessor() = succ and
+ (
+ /* Normal control flow */
+ not pred.getAnExceptionalSuccessor() = succ
+ or
+ /* Re-raise the current exception, propagating to the successor */
+ pred instanceof ReraisingNode
+ )
+ )
+ )
}
-private predicate current_exception(ClassObject ex, BasicBlock b) {
+private predicate current_exception(ClassValue ex, BasicBlock b) {
exists(RaisingNode r |
r.viableExceptionEdge(b.getNode(0), ex) and not b.getNode(0) instanceof ExceptFlowNode
)
or
- exists(BasicBlock prev |
+ exists(BasicBlock prev |
current_exception(ex, prev) and
exists(ControlFlowNode pred, ControlFlowNode succ |
- pred = prev.getLastNode() and succ = b.getNode(0) |
- pred.getASuccessor() = succ and
- (/* Normal control flow */
- not pred.getAnExceptionalSuccessor() = succ or
- /* Re-raise the current exception, propagating to the successor */
- pred instanceof ReraisingNode)
+ pred = prev.getLastNode() and succ = b.getNode(0)
+ |
+ pred.getASuccessor() = succ and
+ (
+ /* Normal control flow */
+ not pred.getAnExceptionalSuccessor() = succ
+ or
+ /* Re-raise the current exception, propagating to the successor */
+ pred instanceof ReraisingNode
+ )
)
)
}
private predicate unknown_current_exception(BasicBlock b) {
exists(RaisingNode r |
- r.raisesUnknownType() and
+ r.raisesUnknownType() and
r.getAnExceptionalSuccessor() = b.getNode(0) and
not b.getNode(0) instanceof ExceptFlowNode
)
or
- exists(BasicBlock prev |
+ exists(BasicBlock prev |
unknown_current_exception(prev) and
exists(ControlFlowNode pred, ControlFlowNode succ |
- pred = prev.getLastNode() and succ = b.getNode(0) |
- pred.getASuccessor() = succ and
+ pred = prev.getLastNode() and succ = b.getNode(0)
+ |
+ pred.getASuccessor() = succ and
(not pred.getAnExceptionalSuccessor() = succ or pred instanceof ReraisingNode)
)
)
}
/** INTERNAL -- Use FunctionObject.getARaisedType() instead */
-predicate scope_raises(ClassObject ex, Scope s) {
- exists(BasicBlock b |
+predicate scope_raises_objectapi(ClassObject ex, Scope s) {
+ exists(BasicBlock b |
+ current_exception_objectapi(ex, b) and
+ b.getLastNode().isExceptionalExit(s)
+ |
+ b.getLastNode() instanceof ReraisingNode
+ )
+ or
+ exists(RaisingNode r | r.viableExceptionalExit_objectapi(s, ex))
+}
+
+/** INTERNAL -- Use FunctionObject.getARaisedType() instead */
+predicate scope_raises(ClassValue ex, Scope s) {
+ exists(BasicBlock b |
current_exception(ex, b) and
- b.getLastNode().isExceptionalExit(s) |
+ b.getLastNode().isExceptionalExit(s)
+ |
b.getLastNode() instanceof ReraisingNode
)
or
@@ -226,9 +350,10 @@ predicate scope_raises(ClassObject ex, Scope s) {
/** INTERNAL -- Use FunctionObject.raisesUnknownType() instead */
predicate scope_raises_unknown(Scope s) {
- exists(BasicBlock b |
- b.getLastNode() instanceof ReraisingNode
- and b.getLastNode().isExceptionalExit(s) |
+ exists(BasicBlock b |
+ b.getLastNode() instanceof ReraisingNode and
+ b.getLastNode().isExceptionalExit(s)
+ |
unknown_current_exception(b)
)
or
@@ -238,117 +363,120 @@ predicate scope_raises_unknown(Scope s) {
)
}
-
/** ControlFlowNode for an 'except' statement. */
class ExceptFlowNode extends ControlFlowNode {
-
- ExceptFlowNode() {
- this.getNode() instanceof ExceptStmt
- }
+ ExceptFlowNode() { this.getNode() instanceof ExceptStmt }
ControlFlowNode getType() {
exists(ExceptStmt ex |
this.getBasicBlock().dominates(result.getBasicBlock()) and
- ex = this.getNode() and result = ex.getType().getAFlowNode()
+ ex = this.getNode() and
+ result = ex.getType().getAFlowNode()
)
}
ControlFlowNode getName() {
exists(ExceptStmt ex |
this.getBasicBlock().dominates(result.getBasicBlock()) and
- ex = this.getNode() and result = ex.getName().getAFlowNode()
+ ex = this.getNode() and
+ result = ex.getName().getAFlowNode()
)
}
private predicate handledObject_objectapi(Object obj, ClassObject cls, ControlFlowNode origin) {
this.getType().refersTo(obj, cls, origin)
or
- exists(Object tup |
- this.handledObject_objectapi(tup, theTupleType(), _) |
+ exists(Object tup | this.handledObject_objectapi(tup, theTupleType(), _) |
element_from_tuple_objectapi(tup).refersTo(obj, cls, origin)
)
}
-
+
private predicate handledObject(Value val, ClassValue cls, ControlFlowNode origin) {
val.getClass() = cls and
(
this.getType().pointsTo(val, origin)
or
- exists(TupleValue tup |
- this.handledObject(tup, ClassValue::tuple(), _) |
+ exists(TupleValue tup | this.handledObject(tup, ClassValue::tuple(), _) |
val = tup.getItem(_) and origin = val.getOrigin()
)
)
}
/** Gets the inferred type(s) that are handled by this node, splitting tuples if possible. */
- pragma [noinline]
+ pragma[noinline]
predicate handledException_objectapi(Object obj, ClassObject cls, ControlFlowNode origin) {
this.handledObject_objectapi(obj, cls, origin) and not cls = theTupleType()
or
- not exists(this.getNode().(ExceptStmt).getType()) and obj = theBaseExceptionType() and cls = theTypeType() and
+ not exists(this.getNode().(ExceptStmt).getType()) and
+ obj = theBaseExceptionType() and
+ cls = theTypeType() and
origin = this
}
-
+
/** Gets the inferred type(s) that are handled by this node, splitting tuples if possible. */
- pragma [noinline]
+ pragma[noinline]
predicate handledException(Value val, ClassValue cls, ControlFlowNode origin) {
this.handledObject(val, cls, origin) and not cls = ClassValue::tuple()
or
- not exists(this.getNode().(ExceptStmt).getType()) and val = ClassValue::baseException() and cls = ClassValue::type() and
+ not exists(this.getNode().(ExceptStmt).getType()) and
+ val = ClassValue::baseException() and
+ cls = ClassValue::type() and
origin = this
}
-
-
/** Whether this `except` handles `cls` */
- predicate handles(ClassObject cls) {
- exists(ClassObject handled |
- this.handledException_objectapi(handled, _, _) |
+ predicate handles_objectapi(ClassObject cls) {
+ exists(ClassObject handled | this.handledException_objectapi(handled, _, _) |
cls.getAnImproperSuperType() = handled
)
}
+ /** Whether this `except` handles `cls` */
+ predicate handles(ClassValue cls) {
+ exists(ClassValue handled | this.handledException(handled, _, _) |
+ cls.getASuperType() = handled
+ )
+ }
}
private ControlFlowNode element_from_tuple_objectapi(Object tuple) {
- exists(Tuple t |
- t = tuple.getOrigin() and result = t.getAnElt().getAFlowNode()
- )
+ exists(Tuple t | t = tuple.getOrigin() and result = t.getAnElt().getAFlowNode())
}
-/** A Reraising node is the node at the end of a finally block (on the exceptional branch)
+/**
+ * A Reraising node is the node at the end of a finally block (on the exceptional branch)
* that reraises the current exception.
*/
class ReraisingNode extends RaisingNode {
-
ReraisingNode() {
not this.getNode() instanceof Raise and
in_finally(this) and
- forall(ControlFlowNode succ |
- succ = this.getASuccessor() |
+ forall(ControlFlowNode succ | succ = this.getASuccessor() |
succ = this.getAnExceptionalSuccessor()
)
}
/** Gets a class that may be raised by this node */
- override ClassObject getARaisedType() {
+ override ClassObject getARaisedType_objectapi() {
+ exists(BasicBlock b |
+ current_exception_objectapi(result, b) and
+ b.getNode(_) = this
+ )
+ }
+
+ /** Gets a class that may be raised by this node */
+ override ClassValue getARaisedType() {
exists(BasicBlock b |
current_exception(result, b) and
b.getNode(_) = this
)
}
-
}
private predicate in_finally(ControlFlowNode n) {
- exists(Stmt f |
- exists(Try t | f = t.getAFinalstmt()) |
- f = n.getNode()
+ exists(Stmt f | exists(Try t | f = t.getAFinalstmt()) |
+ f = n.getNode()
or
f.containsInScope(n.getNode())
)
}
-
-
-
From 2a7b77c0e174a63411bb395535a5af23af8b8885 Mon Sep 17 00:00:00 2001
From: Rebecca Valentine
Date: Thu, 2 Apr 2020 12:18:07 -0700
Subject: [PATCH 0047/1298] Python: ObjectAPI to ValueAPI:
WrongNumberArgumentsInCall: Adds new version of FunctionObject.qll
---
.../semmle/python/types/FunctionObject.qll | 248 ++++++------------
1 file changed, 80 insertions(+), 168 deletions(-)
diff --git a/python/ql/src/semmle/python/types/FunctionObject.qll b/python/ql/src/semmle/python/types/FunctionObject.qll
index 4e03764933d..68e97901c6f 100644
--- a/python/ql/src/semmle/python/types/FunctionObject.qll
+++ b/python/ql/src/semmle/python/types/FunctionObject.qll
@@ -9,22 +9,13 @@ private import semmle.python.types.Builtins
/** A function object, whether written in Python or builtin */
abstract class FunctionObject extends Object {
+ CallableValue theCallable() { result.(ObjectInternal).getSource() = this }
- CallableValue theCallable() {
- result.(ObjectInternal).getSource() = this
- }
+ predicate isOverridingMethod() { exists(Object f | this.overrides(f)) }
- predicate isOverridingMethod() {
- exists(Object f | this.overrides(f))
- }
+ predicate isOverriddenMethod() { exists(Object f | f.overrides(this)) }
- predicate isOverriddenMethod() {
- exists(Object f | f.overrides(this))
- }
-
- Function getFunction() {
- result = ((CallableExpr)this.getOrigin()).getInnerScope()
- }
+ Function getFunction() { result = this.getOrigin().(CallableExpr).getInnerScope() }
/** This function always returns None, meaning that its return value should be disregarded */
abstract predicate isProcedure();
@@ -39,17 +30,13 @@ abstract class FunctionObject extends Object {
abstract predicate raisesUnknownType();
/** Use descriptiveString() instead. */
- deprecated string prettyString() {
- result = this.descriptiveString()
- }
+ deprecated string prettyString() { result = this.descriptiveString() }
/** Gets a longer, more descriptive version of toString() */
abstract string descriptiveString();
/** Gets a call-site from where this function is called as a function */
- CallNode getAFunctionCall() {
- result.getFunction().inferredValue() = theCallable()
- }
+ CallNode getAFunctionCall() { result.getFunction().inferredValue() = theCallable() }
/** Gets a call-site from where this function is called as a method */
CallNode getAMethodCall() {
@@ -60,37 +47,38 @@ abstract class FunctionObject extends Object {
}
/** Gets a call-site from where this function is called */
- ControlFlowNode getACall() {
- result = theCallable().getACall()
- }
+ ControlFlowNode getACall() { result = theCallable().getACall() }
/** Gets a call-site from where this function is called, given the `context` */
ControlFlowNode getACall(Context caller_context) {
result = theCallable().getACall(caller_context)
}
- /** Gets the `ControlFlowNode` that will be passed as the nth argument to `this` when called at `call`.
- This predicate will correctly handle `x.y()`, treating `x` as the zeroth argument.
- */
+ /**
+ * Gets the `ControlFlowNode` that will be passed as the nth argument to `this` when called at `call`.
+ * This predicate will correctly handle `x.y()`, treating `x` as the zeroth argument.
+ */
ControlFlowNode getArgumentForCall(CallNode call, int n) {
result = theCallable().getArgumentForCall(call, n)
}
- /** Gets the `ControlFlowNode` that will be passed as the named argument to `this` when called at `call`.
- This predicate will correctly handle `x.y()`, treating `x` as the self argument.
- */
+ /**
+ * Gets the `ControlFlowNode` that will be passed as the named argument to `this` when called at `call`.
+ * This predicate will correctly handle `x.y()`, treating `x` as the self argument.
+ */
ControlFlowNode getNamedArgumentForCall(CallNode call, string name) {
result = theCallable().getNamedArgumentForCall(call, name)
}
- /** Whether this function never returns. This is an approximation.
+ /**
+ * Whether this function never returns. This is an approximation.
*/
- predicate neverReturns() {
- theCallable().neverReturns()
- }
+ predicate neverReturns() { theCallable().neverReturns() }
- /** Whether this is a "normal" method, that is, it is exists as a class attribute
- * which is not wrapped and not the __new__ method. */
+ /**
+ * Whether this is a "normal" method, that is, it is exists as a class attribute
+ * which is not wrapped and not the __new__ method.
+ */
predicate isNormalMethod() {
exists(ClassObject cls, string name |
cls.declaredAttribute(name) = this and
@@ -113,7 +101,8 @@ abstract class FunctionObject extends Object {
)
}
- /** Gets the qualified name for this function object.
+ /**
+ * Gets the qualified name for this function object.
* Should return the same name as the `__qualname__` attribute on functions in Python 3.
*/
abstract string getQualifiedName();
@@ -129,59 +118,39 @@ abstract class FunctionObject extends Object {
}
/** Gets a class that this function may return */
- ClassObject getAnInferredReturnType() {
- result = this.(BuiltinCallable).getAReturnType()
- }
-
- predicate isAbstract() {
- this.getARaisedType() = theNotImplementedErrorType()
- }
+ ClassObject getAnInferredReturnType() { result = this.(BuiltinCallable).getAReturnType() }
+ predicate isAbstract() { this.getARaisedType() = theNotImplementedErrorType() }
}
class PyFunctionObject extends FunctionObject {
+ PyFunctionObject() { any(PythonFunctionObjectInternal f).getOrigin() = this }
- PyFunctionObject() {
- any(PythonFunctionObjectInternal f).getOrigin() = this
- }
-
- override string toString() {
- result = "Function " + this.getName()
- }
+ override string toString() { result = "Function " + this.getName() }
override string getName() {
- result = ((FunctionExpr)this.getOrigin()).getName()
+ result = this.getOrigin().(FunctionExpr).getName()
or
this.getOrigin() instanceof Lambda and result = "lambda"
}
/** Whether this function is a procedure, that is, it has no explicit return statement and is not a generator function */
- override predicate isProcedure() {
- this.getFunction().isProcedure()
- }
+ override predicate isProcedure() { this.getFunction().isProcedure() }
- override ClassObject getARaisedType() {
- scope_raises(result, this.getFunction())
- }
+ override ClassObject getARaisedType() { scope_raises_objectapi(result, this.getFunction()) }
- override predicate raisesUnknownType() {
- scope_raises_unknown(this.getFunction())
- }
+ override predicate raisesUnknownType() { scope_raises_unknown(this.getFunction()) }
/** Gets a control flow node corresponding to the value of a return statement */
- ControlFlowNode getAReturnedNode() {
- result = this.getFunction().getAReturnValueFlowNode()
- }
+ ControlFlowNode getAReturnedNode() { result = this.getFunction().getAReturnValueFlowNode() }
override string descriptiveString() {
- if this.getFunction().isMethod() then (
- exists(Class cls |
- this.getFunction().getScope() = cls |
+ if this.getFunction().isMethod()
+ then
+ exists(Class cls | this.getFunction().getScope() = cls |
result = "method " + this.getQualifiedName()
)
- ) else (
- result = "function " + this.getQualifiedName()
- )
+ else result = "function " + this.getQualifiedName()
}
override int minParameters() {
@@ -194,16 +163,13 @@ class PyFunctionObject extends FunctionObject {
override int maxParameters() {
exists(Function f |
f = this.getFunction() and
- if exists(f.getVararg()) then
- result = 2147483647 // INT_MAX
- else
- result = count(f.getAnArg())
+ if exists(f.getVararg())
+ then result = 2147483647 // INT_MAX
+ else result = count(f.getAnArg())
)
}
- override string getQualifiedName() {
- result = this.getFunction().getQualifiedName()
- }
+ override string getQualifiedName() { result = this.getFunction().getQualifiedName() }
predicate unconditionallyReturnsParameter(int n) {
exists(SsaVariable pvar |
@@ -220,7 +186,9 @@ class PyFunctionObject extends FunctionObject {
/** Factored out to help join ordering */
private predicate implicitlyReturns(Object none_, ClassObject noneType) {
- noneType = theNoneType() and not this.getFunction().isGenerator() and none_ = theNoneObject() and
+ noneType = theNoneType() and
+ not this.getFunction().isGenerator() and
+ none_ = theNoneObject() and
(
not exists(this.getAReturnedNode()) and exists(this.getFunction().getANormalExit())
or
@@ -232,9 +200,10 @@ class PyFunctionObject extends FunctionObject {
override ClassObject getAnInferredReturnType() {
this.getFunction().isGenerator() and result = theGeneratorType()
or
- not this.neverReturns() and not this.getFunction().isGenerator() and
+ not this.neverReturns() and
+ not this.getFunction().isGenerator() and
(
- this.(PyFunctionObject).getAReturnedNode().refersTo( _, result, _)
+ this.(PyFunctionObject).getAReturnedNode().refersTo(_, result, _)
or
this.implicitlyReturns(_, result)
)
@@ -243,18 +212,13 @@ class PyFunctionObject extends FunctionObject {
ParameterDefinition getParameter(int n) {
result.getDefiningNode().getNode() = this.getFunction().getArg(n)
}
-
}
abstract class BuiltinCallable extends FunctionObject {
-
abstract ClassObject getAReturnType();
override predicate isProcedure() {
- forex(ClassObject rt |
- rt = this.getAReturnType() |
- rt = theNoneType()
- )
+ forex(ClassObject rt | rt = this.getAReturnType() | rt = theNoneType())
}
abstract override string getQualifiedName();
@@ -262,18 +226,13 @@ abstract class BuiltinCallable extends FunctionObject {
override ControlFlowNode getArgumentForCall(CallNode call, int n) {
call = this.getACall() and result = call.getArg(n)
}
-
}
class BuiltinMethodObject extends BuiltinCallable {
-
- BuiltinMethodObject() {
- any(BuiltinMethodObjectInternal m).getBuiltin() = this
- }
+ BuiltinMethodObject() { any(BuiltinMethodObjectInternal m).getBuiltin() = this }
override string getQualifiedName() {
- exists(ClassObject cls |
- cls.asBuiltin().getMember(_) = this.asBuiltin() |
+ exists(ClassObject cls | cls.asBuiltin().getMember(_) = this.asBuiltin() |
result = cls.getName() + "." + this.getName()
)
or
@@ -281,17 +240,11 @@ class BuiltinMethodObject extends BuiltinCallable {
result = this.getName()
}
- override string descriptiveString() {
- result = "builtin-method " + this.getQualifiedName()
- }
+ override string descriptiveString() { result = "builtin-method " + this.getQualifiedName() }
- override string getName() {
- result = this.asBuiltin().getName()
- }
+ override string getName() { result = this.asBuiltin().getName() }
- override string toString() {
- result = "Builtin-method " + this.getName()
- }
+ override string toString() { result = "Builtin-method " + this.getName() }
override ClassObject getARaisedType() {
/* Information is unavailable for C code in general */
@@ -303,41 +256,23 @@ class BuiltinMethodObject extends BuiltinCallable {
any()
}
- override int minParameters() {
- none()
- }
+ override int minParameters() { none() }
- override int maxParameters() {
- none()
- }
-
- override ClassObject getAReturnType() {
- ext_rettype(this.asBuiltin(), result.asBuiltin())
- }
+ override int maxParameters() { none() }
+ override ClassObject getAReturnType() { ext_rettype(this.asBuiltin(), result.asBuiltin()) }
}
class BuiltinFunctionObject extends BuiltinCallable {
+ BuiltinFunctionObject() { any(BuiltinFunctionObjectInternal f).getBuiltin() = this }
- BuiltinFunctionObject() {
- any(BuiltinFunctionObjectInternal f).getBuiltin() = this
- }
+ override string getName() { result = this.asBuiltin().getName() }
- override string getName() {
- result = this.asBuiltin().getName()
- }
+ override string getQualifiedName() { result = this.getName() }
- override string getQualifiedName() {
- result = this.getName()
- }
+ override string toString() { result = "Builtin-function " + this.getName() }
- override string toString() {
- result = "Builtin-function " + this.getName()
- }
-
- override string descriptiveString() {
- result = "builtin-function " + this.getName()
- }
+ override string descriptiveString() { result = "builtin-function " + this.getName() }
override ClassObject getARaisedType() {
/* Information is unavailable for C code in general */
@@ -350,16 +285,19 @@ class BuiltinFunctionObject extends BuiltinCallable {
}
override ClassObject getAReturnType() {
- /* Enumerate the types of a few builtin functions, that the CPython analysis misses.
- */
+ /*
+ * Enumerate the types of a few builtin functions, that the CPython analysis misses.
+ */
+
this = Object::builtin("hex") and result = theStrType()
or
this = Object::builtin("oct") and result = theStrType()
or
this = Object::builtin("intern") and result = theStrType()
or
- /* Fix a few minor inaccuracies in the CPython analysis */
- ext_rettype(this.asBuiltin(), result.asBuiltin()) and not (
+ /* Fix a few minor inaccuracies in the CPython analysis */
+ ext_rettype(this.asBuiltin(), result.asBuiltin()) and
+ not (
this = Object::builtin("__import__") and result = theNoneType()
or
this = Object::builtin("compile") and result = theNoneType()
@@ -370,63 +308,37 @@ class BuiltinFunctionObject extends BuiltinCallable {
)
}
- override int minParameters() {
- none()
- }
-
- override int maxParameters() {
- none()
- }
+ override int minParameters() { none() }
+ override int maxParameters() { none() }
}
/** DEPRECATED -- Use `Object::builtin("apply")` instead. */
-deprecated Object theApplyFunction() {
- result = Object::builtin("apply")
-}
+deprecated Object theApplyFunction() { result = Object::builtin("apply") }
/** DEPRECATED -- Use `Object::builtin("hasattr")` instead. */
-deprecated Object theHasattrFunction() {
- result = Object::builtin("hasattr")
-}
+deprecated Object theHasattrFunction() { result = Object::builtin("hasattr") }
/** DEPRECATED -- Use `Object::builtin("len")` instead. */
-deprecated Object theLenFunction() {
- result = Object::builtin("len")
-}
+deprecated Object theLenFunction() { result = Object::builtin("len") }
/** DEPRECATED -- Use `Object::builtin("format")` instead. */
-deprecated Object theFormatFunction() {
- result = Object::builtin("format")
-}
+deprecated Object theFormatFunction() { result = Object::builtin("format") }
/** DEPRECATED -- Use `Object::builtin("open")` instead. */
-deprecated Object theOpenFunction() {
- result = Object::builtin("open")
-}
+deprecated Object theOpenFunction() { result = Object::builtin("open") }
/** DEPRECATED -- Use `Object::builtin("print")` instead. */
-deprecated Object thePrintFunction() {
- result = Object::builtin("print")
-}
+deprecated Object thePrintFunction() { result = Object::builtin("print") }
/** DEPRECATED -- Use `Object::builtin("input")` instead. */
-deprecated Object theInputFunction() {
- result = Object::builtin("input")
-}
+deprecated Object theInputFunction() { result = Object::builtin("input") }
/** DEPRECATED -- Use `Object::builtin("locals")` instead. */
-deprecated Object theLocalsFunction() {
- result = Object::builtin("locals")
-}
+deprecated Object theLocalsFunction() { result = Object::builtin("locals") }
/** DEPRECATED -- Use `Object::builtin("globals")()` instead. */
-deprecated Object theGlobalsFunction() {
- result = Object::builtin("globals")
-}
+deprecated Object theGlobalsFunction() { result = Object::builtin("globals") }
/** DEPRECATED -- Use `Object::builtin("sysExit()` instead. */
-deprecated Object theExitFunctionObject() {
- result = ModuleObject::named("sys").attr("exit")
-}
-
+deprecated Object theExitFunctionObject() { result = ModuleObject::named("sys").attr("exit") }
From f05b2af69dd47846ae41bc9eef56ef9b5a8d685b Mon Sep 17 00:00:00 2001
From: Grzegorz Golawski
Date: Fri, 3 Apr 2020 00:27:51 +0200
Subject: [PATCH 0048/1298] Move to experimental
---
.../Security/CWE/CWE-016/SpringBootActuators.java | 0
.../Security/CWE/CWE-016/SpringBootActuators.qhelp | 3 +++
.../Security/CWE/CWE-016/SpringBootActuators.ql | 0
.../Security/CWE/CWE-016/SpringBootActuators.qll | 0
.../query-tests/security/CWE-016/SpringBootActuators.java | 2 +-
.../query-tests/security/CWE-016/SpringBootActuators.qlref | 0
6 files changed, 4 insertions(+), 1 deletion(-)
rename java/ql/src/{ => experimental}/Security/CWE/CWE-016/SpringBootActuators.java (100%)
rename java/ql/src/{ => experimental}/Security/CWE/CWE-016/SpringBootActuators.qhelp (92%)
rename java/ql/src/{ => experimental}/Security/CWE/CWE-016/SpringBootActuators.ql (100%)
rename java/ql/src/{ => experimental}/Security/CWE/CWE-016/SpringBootActuators.qll (100%)
rename java/ql/test/{ => experimental}/query-tests/security/CWE-016/SpringBootActuators.java (97%)
rename java/ql/test/{ => experimental}/query-tests/security/CWE-016/SpringBootActuators.qlref (100%)
diff --git a/java/ql/src/Security/CWE/CWE-016/SpringBootActuators.java b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.java
similarity index 100%
rename from java/ql/src/Security/CWE/CWE-016/SpringBootActuators.java
rename to java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.java
diff --git a/java/ql/src/Security/CWE/CWE-016/SpringBootActuators.qhelp b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qhelp
similarity index 92%
rename from java/ql/src/Security/CWE/CWE-016/SpringBootActuators.qhelp
rename to java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qhelp
index 1e2fe651860..53ee653aaff 100644
--- a/java/ql/src/Security/CWE/CWE-016/SpringBootActuators.qhelp
+++ b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qhelp
@@ -32,5 +32,8 @@ the actuator endpoints.
Spring Boot documentation:
Actuators.
+
+Exploiting Spring Boot Actuators
+
diff --git a/java/ql/src/Security/CWE/CWE-016/SpringBootActuators.ql b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.ql
similarity index 100%
rename from java/ql/src/Security/CWE/CWE-016/SpringBootActuators.ql
rename to java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.ql
diff --git a/java/ql/src/Security/CWE/CWE-016/SpringBootActuators.qll b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll
similarity index 100%
rename from java/ql/src/Security/CWE/CWE-016/SpringBootActuators.qll
rename to java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll
diff --git a/java/ql/test/query-tests/security/CWE-016/SpringBootActuators.java b/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.java
similarity index 97%
rename from java/ql/test/query-tests/security/CWE-016/SpringBootActuators.java
rename to java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.java
index 920a1ff05c0..b554a7bac7e 100644
--- a/java/ql/test/query-tests/security/CWE-016/SpringBootActuators.java
+++ b/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.java
@@ -1,7 +1,7 @@
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-public class ActuatorSecurityConfig {
+public class SpringBootActuators {
protected void configure(HttpSecurity http) throws Exception {
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests(requests -> requests.anyRequest().permitAll());
}
diff --git a/java/ql/test/query-tests/security/CWE-016/SpringBootActuators.qlref b/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.qlref
similarity index 100%
rename from java/ql/test/query-tests/security/CWE-016/SpringBootActuators.qlref
rename to java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.qlref
From 6ca963a8c89cfe541fefeb7a259f099554a8ffec Mon Sep 17 00:00:00 2001
From: Grzegorz Golawski
Date: Fri, 3 Apr 2020 00:30:02 +0200
Subject: [PATCH 0049/1298] Fix
---
.../experimental/Security/CWE/CWE-016/SpringBootActuators.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.java b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.java
index 63b9aadbc10..538620550ef 100644
--- a/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.java
+++ b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.java
@@ -1,5 +1,5 @@
@Configuration(proxyBeanMethods = false)
-public class ActuatorSecurity extends WebSecurityConfigurerAdapter {
+public class SpringBootActuators extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
From 8d81b885c619245fd3a4a2a06aaa6e1b123b9c0c Mon Sep 17 00:00:00 2001
From: Tom Hvitved
Date: Thu, 2 Apr 2020 10:41:53 +0200
Subject: [PATCH 0050/1298] C#: Unset `Platform` env variable when invoking
`vcvarsall.bat`
---
csharp/autobuilder/Semmle.Autobuild/CommandBuilder.cs | 7 +++++--
csharp/autobuilder/Semmle.Autobuild/MsBuildRule.cs | 7 +++++++
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/csharp/autobuilder/Semmle.Autobuild/CommandBuilder.cs b/csharp/autobuilder/Semmle.Autobuild/CommandBuilder.cs
index 7b95e495697..264436a1ea7 100644
--- a/csharp/autobuilder/Semmle.Autobuild/CommandBuilder.cs
+++ b/csharp/autobuilder/Semmle.Autobuild/CommandBuilder.cs
@@ -169,7 +169,7 @@ namespace Semmle.Autobuild
arguments.Append(" &&");
}
- public CommandBuilder RunCommand(string exe, string argumentsOpt = null)
+ public CommandBuilder RunCommand(string exe, string argumentsOpt = null, bool quoteExe = true)
{
var (exe0, arg0) =
escapingMode == EscapeMode.Process && exe.EndsWith(".exe", System.StringComparison.Ordinal)
@@ -183,7 +183,10 @@ namespace Semmle.Autobuild
}
else
{
- QuoteArgument(exe0);
+ if (quoteExe)
+ QuoteArgument(exe0);
+ else
+ Argument(exe0);
}
Argument(arg0);
Argument(argumentsOpt);
diff --git a/csharp/autobuilder/Semmle.Autobuild/MsBuildRule.cs b/csharp/autobuilder/Semmle.Autobuild/MsBuildRule.cs
index b0ee01b8d3c..4e435f4bb9f 100644
--- a/csharp/autobuilder/Semmle.Autobuild/MsBuildRule.cs
+++ b/csharp/autobuilder/Semmle.Autobuild/MsBuildRule.cs
@@ -57,7 +57,14 @@ namespace Semmle.Autobuild
var command = new CommandBuilder(builder.Actions);
if (vsTools != null)
+ {
command.CallBatFile(vsTools.Path);
+ // `vcvarsall.bat` sets a default Platform environment variable,
+ // which may not be compatible with the supported platforms of the
+ // given project/solution. Unsetting it means that the default platform
+ // of the project/solution is used instead.
+ command.RunCommand("set Platform=&& type NUL", quoteExe: false);
+ }
builder.MaybeIndex(command, MsBuild);
command.QuoteArgument(projectOrSolution.FullPath);
From 79d7ea36ffef2cf1759ee4807f2198edcf14b8e6 Mon Sep 17 00:00:00 2001
From: ggolawski <35563296+ggolawski@users.noreply.github.com>
Date: Fri, 3 Apr 2020 21:36:34 +0200
Subject: [PATCH 0051/1298] Update
java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll
Co-Authored-By: Anders Schack-Mulligen
---
.../CWE/CWE-016/SpringBootActuators.qll | 22 +++++++++----------
1 file changed, 10 insertions(+), 12 deletions(-)
diff --git a/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll
index 36223e4b6e6..658983f2437 100644
--- a/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll
+++ b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll
@@ -86,16 +86,12 @@ class PermitAllCall extends MethodAccess {
/** Holds if `permitAll` is called on request(s) mapped to actuator endpoint(s). */
predicate permitsSpringBootActuators() {
- exists(
- RequestMatcherCall requestMatcherCall, RequestMatchersCall requestMatchersCall,
- RegistryRequestMatchersCall registryRequestMatchersCall,
- AuthorizeRequestsCall authorizeRequestsCall, AnyRequestCall anyRequestCall
- |
+ exists(AuthorizeRequestsCall authorizeRequestsCall |
// .requestMatcher(EndpointRequest).authorizeRequests([...]).[...]
- authorizeRequestsCall.getQualifier() = requestMatcherCall
+ authorizeRequestsCall.getQualifier() instanceof RequestMatcherCall
or
// .requestMatchers(matcher -> EndpointRequest).authorizeRequests([...]).[...]
- authorizeRequestsCall.getQualifier() = requestMatchersCall
+ authorizeRequestsCall.getQualifier() instanceof RequestMatchersCall
or
// http.authorizeRequests([...]).[...]
authorizeRequestsCall.getQualifier() instanceof VarAccess
@@ -104,20 +100,22 @@ class PermitAllCall extends MethodAccess {
// [...].authorizeRequests(r -> r.requestMatchers(EndpointRequest).permitAll())
authorizeRequestsCall.getArgument(0).(LambdaExpr).getExprBody() = this and
(
- this.getQualifier() = anyRequestCall or
- this.getQualifier() = registryRequestMatchersCall
+ this.getQualifier() instanceof AnyRequestCall or
+ this.getQualifier() instanceof RegistryRequestMatchersCall
)
or
// [...].authorizeRequests().requestMatchers(EndpointRequest).permitAll() or
// [...].authorizeRequests().anyRequest().permitAll()
authorizeRequestsCall.getNumArgument() = 0 and
- (
+ exists(RegistryRequestMatchersCall registryRequestMatchersCall |
registryRequestMatchersCall.getQualifier() = authorizeRequestsCall and
this.getQualifier() = registryRequestMatchersCall
)
or
- anyRequestCall.getQualifier() = authorizeRequestsCall and
- this.getQualifier() = anyRequestCall
+ exists(AnyRequestCall anyRequestCall |
+ anyRequestCall.getQualifier() = authorizeRequestsCall and
+ this.getQualifier() = anyRequestCall
+ )
)
}
}
From 1d8da905ac02510bec59271e23012ee48cd9d741 Mon Sep 17 00:00:00 2001
From: Grzegorz Golawski
Date: Fri, 3 Apr 2020 21:44:13 +0200
Subject: [PATCH 0052/1298] Make the test runnable via codeql test run
---
java/ql/src/experimental/qlpack.yml | 3 ++
java/ql/test/experimental/qlpack.yml | 4 ++
.../CWE-016/SpringBootActuators.expected | 7 +++
.../query-tests/security/CWE-016/options | 1 +
.../beans/factory/BeanFactory.java | 3 ++
.../factory/HierarchicalBeanFactory.java | 3 ++
.../beans/factory/ListableBeanFactory.java | 3 ++
.../security/servlet/EndpointRequest.java | 15 +++++++
.../ApplicationContextRequestMatcher.java | 5 +++
.../context/ApplicationContext.java | 9 ++++
.../context/ApplicationEventPublisher.java | 6 +++
.../context/MessageSource.java | 3 ++
.../core/env/EnvironmentCapable.java | 3 ++
.../core/io/ResourceLoader.java | 3 ++
.../io/support/ResourcePatternResolver.java | 5 +++
.../security/config/Customizer.java | 6 +++
.../AbstractConfiguredSecurityBuilder.java | 4 ++
.../annotation/AbstractSecurityBuilder.java | 3 ++
.../config/annotation/SecurityBuilder.java | 3 ++
.../config/annotation/SecurityConfigurer.java | 3 ++
.../annotation/SecurityConfigurerAdapter.java | 4 ++
.../web/AbstractRequestMatcherRegistry.java | 13 ++++++
.../annotation/web/HttpSecurityBuilder.java | 7 +++
.../annotation/web/builders/HttpSecurity.java | 43 +++++++++++++++++++
...ConfigAttributeRequestMatcherRegistry.java | 6 +++
.../configurers/AbstractHttpConfigurer.java | 8 ++++
.../AbstractInterceptUrlConfigurer.java | 10 +++++
.../ExpressionUrlAuthorizationConfigurer.java | 16 +++++++
.../web/DefaultSecurityFilterChain.java | 3 ++
.../security/web/SecurityFilterChain.java | 3 ++
.../web/util/matcher/RequestMatcher.java | 3 ++
.../web/context/WebApplicationContext.java | 5 +++
32 files changed, 213 insertions(+)
create mode 100644 java/ql/src/experimental/qlpack.yml
create mode 100644 java/ql/test/experimental/qlpack.yml
create mode 100644 java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.expected
create mode 100644 java/ql/test/experimental/query-tests/security/CWE-016/options
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/BeanFactory.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/HierarchicalBeanFactory.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/ListableBeanFactory.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/security/servlet/ApplicationContextRequestMatcher.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/ApplicationContext.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/ApplicationEventPublisher.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/MessageSource.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/env/EnvironmentCapable.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/io/ResourceLoader.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/io/support/ResourcePatternResolver.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/Customizer.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractConfiguredSecurityBuilder.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractSecurityBuilder.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityBuilder.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurer.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurerAdapter.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/HttpSecurityBuilder.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/builders/HttpSecurity.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractConfigAttributeRequestMatcherRegistry.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractHttpConfigurer.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractInterceptUrlConfigurer.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/DefaultSecurityFilterChain.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/SecurityFilterChain.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/util/matcher/RequestMatcher.java
create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/context/WebApplicationContext.java
diff --git a/java/ql/src/experimental/qlpack.yml b/java/ql/src/experimental/qlpack.yml
new file mode 100644
index 00000000000..090a3e8359b
--- /dev/null
+++ b/java/ql/src/experimental/qlpack.yml
@@ -0,0 +1,3 @@
+name: codeql-java-experimental
+version: 0.0.0
+libraryPathDependencies: codeql-java
diff --git a/java/ql/test/experimental/qlpack.yml b/java/ql/test/experimental/qlpack.yml
new file mode 100644
index 00000000000..4b7a7635a6c
--- /dev/null
+++ b/java/ql/test/experimental/qlpack.yml
@@ -0,0 +1,4 @@
+name: codeql-java-experimental-tests
+version: 0.0.0
+libraryPathDependencies: codeql-java-experimental
+extractor: java
diff --git a/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.expected b/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.expected
new file mode 100644
index 00000000000..f2874e3694d
--- /dev/null
+++ b/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.expected
@@ -0,0 +1,7 @@
+| SpringBootActuators.java:6:88:6:120 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. |
+| SpringBootActuators.java:10:5:10:137 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. |
+| SpringBootActuators.java:14:5:14:149 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. |
+| SpringBootActuators.java:18:5:18:101 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. |
+| SpringBootActuators.java:22:5:22:89 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. |
+| SpringBootActuators.java:26:40:26:108 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. |
+| SpringBootActuators.java:30:5:30:113 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. |
diff --git a/java/ql/test/experimental/query-tests/security/CWE-016/options b/java/ql/test/experimental/query-tests/security/CWE-016/options
new file mode 100644
index 00000000000..aeef8fc5abc
--- /dev/null
+++ b/java/ql/test/experimental/query-tests/security/CWE-016/options
@@ -0,0 +1 @@
+//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.2.3
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/BeanFactory.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/BeanFactory.java
new file mode 100644
index 00000000000..692a7ae417d
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/BeanFactory.java
@@ -0,0 +1,3 @@
+package org.springframework.beans.factory;
+
+public interface BeanFactory {}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/HierarchicalBeanFactory.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/HierarchicalBeanFactory.java
new file mode 100644
index 00000000000..5d857ca2df2
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/HierarchicalBeanFactory.java
@@ -0,0 +1,3 @@
+package org.springframework.beans.factory;
+
+public interface HierarchicalBeanFactory extends BeanFactory {}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/ListableBeanFactory.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/ListableBeanFactory.java
new file mode 100644
index 00000000000..d6fe32875da
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/ListableBeanFactory.java
@@ -0,0 +1,3 @@
+package org.springframework.beans.factory;
+
+public interface ListableBeanFactory extends BeanFactory {}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java
new file mode 100644
index 00000000000..5b94a086e8f
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java
@@ -0,0 +1,15 @@
+package org.springframework.boot.actuate.autoconfigure.security.servlet;
+
+import org.springframework.boot.security.servlet.ApplicationContextRequestMatcher;
+import org.springframework.web.context.WebApplicationContext;
+
+public final class EndpointRequest {
+ public static EndpointRequestMatcher toAnyEndpoint() {
+ return null;
+ }
+
+ public static final class EndpointRequestMatcher extends AbstractRequestMatcher {}
+
+ private abstract static class AbstractRequestMatcher
+ extends ApplicationContextRequestMatcher {}
+}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/security/servlet/ApplicationContextRequestMatcher.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/security/servlet/ApplicationContextRequestMatcher.java
new file mode 100644
index 00000000000..19676a1452a
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/security/servlet/ApplicationContextRequestMatcher.java
@@ -0,0 +1,5 @@
+package org.springframework.boot.security.servlet;
+
+import org.springframework.security.web.util.matcher.RequestMatcher;
+
+public abstract class ApplicationContextRequestMatcher implements RequestMatcher {}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/ApplicationContext.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/ApplicationContext.java
new file mode 100644
index 00000000000..e8b0ed28eda
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/ApplicationContext.java
@@ -0,0 +1,9 @@
+package org.springframework.context;
+
+import org.springframework.beans.factory.HierarchicalBeanFactory;
+import org.springframework.beans.factory.ListableBeanFactory;
+import org.springframework.core.env.EnvironmentCapable;
+import org.springframework.core.io.support.ResourcePatternResolver;
+
+public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
+ MessageSource, ApplicationEventPublisher, ResourcePatternResolver {}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/ApplicationEventPublisher.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/ApplicationEventPublisher.java
new file mode 100644
index 00000000000..b4b659ff72e
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/ApplicationEventPublisher.java
@@ -0,0 +1,6 @@
+package org.springframework.context;
+
+@FunctionalInterface
+public interface ApplicationEventPublisher {
+ void publishEvent(Object event);
+}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/MessageSource.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/MessageSource.java
new file mode 100644
index 00000000000..1012702926d
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/MessageSource.java
@@ -0,0 +1,3 @@
+package org.springframework.context;
+
+public interface MessageSource {}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/env/EnvironmentCapable.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/env/EnvironmentCapable.java
new file mode 100644
index 00000000000..09490c33fa5
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/env/EnvironmentCapable.java
@@ -0,0 +1,3 @@
+package org.springframework.core.env;
+
+public interface EnvironmentCapable {}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/io/ResourceLoader.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/io/ResourceLoader.java
new file mode 100644
index 00000000000..0422a77c54c
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/io/ResourceLoader.java
@@ -0,0 +1,3 @@
+package org.springframework.core.io;
+
+public interface ResourceLoader {}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/io/support/ResourcePatternResolver.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/io/support/ResourcePatternResolver.java
new file mode 100644
index 00000000000..b23a5c73cde
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/io/support/ResourcePatternResolver.java
@@ -0,0 +1,5 @@
+package org.springframework.core.io.support;
+
+import org.springframework.core.io.ResourceLoader;
+
+public interface ResourcePatternResolver extends ResourceLoader {}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/Customizer.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/Customizer.java
new file mode 100644
index 00000000000..5037bd499a1
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/Customizer.java
@@ -0,0 +1,6 @@
+package org.springframework.security.config;
+
+@FunctionalInterface
+public interface Customizer {
+ void customize(T t);
+}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractConfiguredSecurityBuilder.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractConfiguredSecurityBuilder.java
new file mode 100644
index 00000000000..6ef43f44d94
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractConfiguredSecurityBuilder.java
@@ -0,0 +1,4 @@
+package org.springframework.security.config.annotation;
+
+public abstract class AbstractConfiguredSecurityBuilder>
+ extends AbstractSecurityBuilder {}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractSecurityBuilder.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractSecurityBuilder.java
new file mode 100644
index 00000000000..c9ee05b5c78
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractSecurityBuilder.java
@@ -0,0 +1,3 @@
+package org.springframework.security.config.annotation;
+
+public abstract class AbstractSecurityBuilder implements SecurityBuilder {}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityBuilder.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityBuilder.java
new file mode 100644
index 00000000000..0ec0cfc30cc
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityBuilder.java
@@ -0,0 +1,3 @@
+package org.springframework.security.config.annotation;
+
+public interface SecurityBuilder {}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurer.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurer.java
new file mode 100644
index 00000000000..bde989db998
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurer.java
@@ -0,0 +1,3 @@
+package org.springframework.security.config.annotation;
+
+public interface SecurityConfigurer> {}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurerAdapter.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurerAdapter.java
new file mode 100644
index 00000000000..f44385219bd
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurerAdapter.java
@@ -0,0 +1,4 @@
+package org.springframework.security.config.annotation;
+
+public abstract class SecurityConfigurerAdapter>
+ implements SecurityConfigurer {}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java
new file mode 100644
index 00000000000..70c3fb15b8f
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java
@@ -0,0 +1,13 @@
+package org.springframework.security.config.annotation.web;
+
+import org.springframework.security.web.util.matcher.RequestMatcher;
+
+public abstract class AbstractRequestMatcherRegistry {
+ public C anyRequest() {
+ return null;
+ }
+
+ public C requestMatchers(RequestMatcher... requestMatchers) {
+ return null;
+ }
+}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/HttpSecurityBuilder.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/HttpSecurityBuilder.java
new file mode 100644
index 00000000000..d69f989a1ed
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/HttpSecurityBuilder.java
@@ -0,0 +1,7 @@
+package org.springframework.security.config.annotation.web;
+
+import org.springframework.security.config.annotation.SecurityBuilder;
+import org.springframework.security.web.DefaultSecurityFilterChain;
+
+public interface HttpSecurityBuilder> extends
+ SecurityBuilder {}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/builders/HttpSecurity.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/builders/HttpSecurity.java
new file mode 100644
index 00000000000..7e4f1dceed4
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/builders/HttpSecurity.java
@@ -0,0 +1,43 @@
+package org.springframework.security.config.annotation.web.builders;
+
+import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder;
+import org.springframework.security.config.annotation.SecurityBuilder;
+import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
+import org.springframework.security.web.DefaultSecurityFilterChain;
+import org.springframework.security.web.util.matcher.RequestMatcher;
+import org.springframework.security.config.Customizer;
+import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
+import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
+
+public final class HttpSecurity extends AbstractConfiguredSecurityBuilder
+ implements SecurityBuilder, HttpSecurityBuilder {
+
+ public HttpSecurity requestMatcher(RequestMatcher requestMatcher) {
+ return this;
+ }
+
+ public HttpSecurity authorizeRequests(
+ Customizer.ExpressionInterceptUrlRegistry> authorizeRequestsCustomizer)
+ throws Exception {
+ return this;
+ }
+
+ public ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry authorizeRequests()
+ throws Exception {
+ return null;
+ }
+
+ public HttpSecurity requestMatchers(Customizer requestMatcherCustomizer) {
+ return this;
+ }
+
+ public RequestMatcherConfigurer requestMatchers() {
+ return null;
+ }
+
+ public final class MvcMatchersRequestMatcherConfigurer extends RequestMatcherConfigurer {
+ }
+
+ public class RequestMatcherConfigurer extends AbstractRequestMatcherRegistry {
+ }
+}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractConfigAttributeRequestMatcherRegistry.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractConfigAttributeRequestMatcherRegistry.java
new file mode 100644
index 00000000000..b6e75cafadb
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractConfigAttributeRequestMatcherRegistry.java
@@ -0,0 +1,6 @@
+package org.springframework.security.config.annotation.web.configurers;
+
+import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
+
+public abstract class AbstractConfigAttributeRequestMatcherRegistry extends
+ AbstractRequestMatcherRegistry {}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractHttpConfigurer.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractHttpConfigurer.java
new file mode 100644
index 00000000000..7a1b56d5f3f
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractHttpConfigurer.java
@@ -0,0 +1,8 @@
+package org.springframework.security.config.annotation.web.configurers;
+
+import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
+import org.springframework.security.web.DefaultSecurityFilterChain;
+
+public abstract class AbstractHttpConfigurer, B extends HttpSecurityBuilder>
+ extends SecurityConfigurerAdapter {}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractInterceptUrlConfigurer.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractInterceptUrlConfigurer.java
new file mode 100644
index 00000000000..c5c56d56709
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractInterceptUrlConfigurer.java
@@ -0,0 +1,10 @@
+package org.springframework.security.config.annotation.web.configurers;
+
+import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
+
+abstract class AbstractInterceptUrlConfigurer, H extends HttpSecurityBuilder>
+ extends AbstractHttpConfigurer {
+ abstract class AbstractInterceptUrlRegistry, T>
+ extends AbstractConfigAttributeRequestMatcherRegistry {
+ }
+}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java
new file mode 100644
index 00000000000..012997dc502
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java
@@ -0,0 +1,16 @@
+package org.springframework.security.config.annotation.web.configurers;
+
+import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
+
+public final class ExpressionUrlAuthorizationConfigurer>
+ extends AbstractInterceptUrlConfigurer, H> {
+ public class ExpressionInterceptUrlRegistry extends
+ ExpressionUrlAuthorizationConfigurer.AbstractInterceptUrlRegistry {
+ }
+
+ public class AuthorizedUrl {
+ public ExpressionInterceptUrlRegistry permitAll() {
+ return null;
+ }
+ }
+}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/DefaultSecurityFilterChain.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/DefaultSecurityFilterChain.java
new file mode 100644
index 00000000000..fbd1ff753e6
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/DefaultSecurityFilterChain.java
@@ -0,0 +1,3 @@
+package org.springframework.security.web;
+
+public final class DefaultSecurityFilterChain implements SecurityFilterChain {}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/SecurityFilterChain.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/SecurityFilterChain.java
new file mode 100644
index 00000000000..4ecef359d1a
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/SecurityFilterChain.java
@@ -0,0 +1,3 @@
+package org.springframework.security.web;
+
+public interface SecurityFilterChain {}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/util/matcher/RequestMatcher.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/util/matcher/RequestMatcher.java
new file mode 100644
index 00000000000..05d7a2552db
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/util/matcher/RequestMatcher.java
@@ -0,0 +1,3 @@
+package org.springframework.security.web.util.matcher;
+
+public interface RequestMatcher {}
diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/context/WebApplicationContext.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/context/WebApplicationContext.java
new file mode 100644
index 00000000000..16b5d13fd6e
--- /dev/null
+++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/context/WebApplicationContext.java
@@ -0,0 +1,5 @@
+package org.springframework.web.context;
+
+import org.springframework.context.ApplicationContext;
+
+public interface WebApplicationContext extends ApplicationContext {}
From 2ad0f5af2df14ca6848e5d32b2a79ab4c4f0efa1 Mon Sep 17 00:00:00 2001
From: Rebecca Valentine
Date: Fri, 3 Apr 2020 20:04:32 -0700
Subject: [PATCH 0053/1298] Python: ObjectAPI to ValueAPI:
WrongNumberArgumentsInCall: ObjectAPI.qll: Adds getAFunctionCall and
getAMethodCall predicates to FunctionValue
---
python/ql/src/semmle/python/objects/ObjectAPI.qll | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll
index 380f42043c7..d24976be013 100644
--- a/python/ql/src/semmle/python/objects/ObjectAPI.qll
+++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll
@@ -594,6 +594,17 @@ abstract class FunctionValue extends CallableValue {
or
result = TBuiltinClassObject(this.(BuiltinMethodObjectInternal).getReturnType())
}
+
+ /** Gets a call-site from where this function is called as a function */
+ CallNode getAFunctionCall() { result.getFunction().pointsTo() = this }
+
+ /** Gets a call-site from where this function is called as a method */
+ CallNode getAMethodCall() {
+ exists(BoundMethodObjectInternal bm |
+ result.getFunction().pointsTo() = bm and
+ bm.getFunction() = this
+ )
+ }
}
/** Class representing Python functions */
From c6fbbb1cd19fca003d0a8b5ba2bb3f23fd377cac Mon Sep 17 00:00:00 2001
From: Rebecca Valentine
Date: Fri, 3 Apr 2020 20:06:43 -0700
Subject: [PATCH 0054/1298] Python: ObjectAPI to ValueAPI:
WrongNumberArgumentsInCall: CallArgs.qll: Fixes too_*_args refs to getA*Call
---
python/ql/src/Expressions/CallArgs.qll | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/python/ql/src/Expressions/CallArgs.qll b/python/ql/src/Expressions/CallArgs.qll
index b071bbac372..c455a3428d9 100644
--- a/python/ql/src/Expressions/CallArgs.qll
+++ b/python/ql/src/Expressions/CallArgs.qll
@@ -159,14 +159,14 @@ predicate too_few_args(Call call, Value callable, int limit) {
not exists(call.getStarargs()) and not exists(call.getKwargs()) and
arg_count(call) < limit and
exists(FunctionValue func | func = get_function_or_initializer(callable) |
- call = func.getACall().getNode() and limit = func.minParameters() and
+ call = func.getAFunctionCall().getNode() and limit = func.minParameters() and
/* The combination of misuse of `mox.Mox().StubOutWithMock()`
* and a bug in mox's implementation of methods results in having to
* pass 1 too few arguments to the mocked function.
*/
not (useOfMoxInModule(call.getEnclosingModule()) and func.isNormalMethod())
or
- call = func.getACall().getNode() and limit = func.minParameters() - 1
+ call = func.getAMethodCall().getNode() and limit = func.minParameters() - 1
or
callable instanceof ClassValue and
call.getAFlowNode() = get_a_call(callable) and limit = func.minParameters() - 1
@@ -199,9 +199,9 @@ predicate too_many_args(Call call, Value callable, int limit) {
func = get_function_or_initializer(callable) and
not func.getScope().hasVarArg() and limit >= 0
|
- call = func.getACall().getNode() and limit = func.maxParameters()
+ call = func.getAFunctionCall().getNode() and limit = func.maxParameters()
or
- call = func.getACall().getNode() and limit = func.maxParameters() - 1
+ call = func.getAMethodCall().getNode() and limit = func.maxParameters() - 1
or
callable instanceof ClassValue and
call.getAFlowNode() = get_a_call(callable) and limit = func.maxParameters() - 1
From f25428b7a9f8e2435a935cca64df53053fdb865c Mon Sep 17 00:00:00 2001
From: Rebecca Valentine
Date: Fri, 3 Apr 2020 20:08:00 -0700
Subject: [PATCH 0055/1298] Python: ObjectAPI to ValueAPI:
WrongNumberArgumentsInCall: Exceptions.qll: Fixes incorrect implementation of
localRaisedType
---
python/ql/src/semmle/python/types/Exceptions.qll | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/python/ql/src/semmle/python/types/Exceptions.qll b/python/ql/src/semmle/python/types/Exceptions.qll
index 9de373f73d4..b194807e4a1 100644
--- a/python/ql/src/semmle/python/types/Exceptions.qll
+++ b/python/ql/src/semmle/python/types/Exceptions.qll
@@ -97,7 +97,7 @@ class RaisingNode extends ControlFlowNode {
(
exists(ControlFlowNode ex |
ex = this.getExceptionNode() and
- (ex.pointsTo(result) or ex.pointsTo(_, result, _))
+ (ex.pointsTo(result) or ex.pointsTo().getClass() = result)
)
or
this.getNode() instanceof ImportExpr and result = ClassValue::importError()
From e0f26d4f7e8b71f06e41e526df07d4cb300aabbc Mon Sep 17 00:00:00 2001
From: Rebecca Valentine
Date: Fri, 3 Apr 2020 20:11:42 -0700
Subject: [PATCH 0056/1298] Python: ObjectAPI to ValueAPI:
WrongNumberArgumentsInCall: Updates expected results
---
.../Functions/overriding/WrongNumberArgumentsInCall.expected | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/python/ql/test/query-tests/Functions/overriding/WrongNumberArgumentsInCall.expected b/python/ql/test/query-tests/Functions/overriding/WrongNumberArgumentsInCall.expected
index 4f29401ce5b..86dd08abf16 100644
--- a/python/ql/test/query-tests/Functions/overriding/WrongNumberArgumentsInCall.expected
+++ b/python/ql/test/query-tests/Functions/overriding/WrongNumberArgumentsInCall.expected
@@ -1,2 +1,2 @@
-| test.py:16:9:16:21 | Attribute() | Call to $@ with too many arguments; should be no more than 0. | test.py:5:5:5:20 | Function meth1 | method Base.meth1 |
-| test.py:17:9:17:20 | Attribute() | Call to $@ with too few arguments; should be no fewer than 1. | test.py:8:5:8:26 | Function meth2 | method Base.meth2 |
+| test.py:16:9:16:21 | Attribute() | Call to $@ with too many arguments; should be no more than 0. | test.py:5:5:5:20 | Function Base.meth1 | method Base.meth1 |
+| test.py:17:9:17:20 | Attribute() | Call to $@ with too few arguments; should be no fewer than 1. | test.py:8:5:8:26 | Function Base.meth2 | method Base.meth2 |
From 7615452b3179939b19ef27c28e9f43a1f09d566a Mon Sep 17 00:00:00 2001
From: Rebecca Valentine
Date: Fri, 3 Apr 2020 20:28:19 -0700
Subject: [PATCH 0057/1298] Python: ObjAPI to ValAPI: WrongNumArgsInCall:
Autoformat CallArgs.qll
---
python/ql/src/Expressions/CallArgs.qll | 39 +++++++++++++++-----------
1 file changed, 22 insertions(+), 17 deletions(-)
diff --git a/python/ql/src/Expressions/CallArgs.qll b/python/ql/src/Expressions/CallArgs.qll
index 1686195f12b..61ce5c7dc8c 100644
--- a/python/ql/src/Expressions/CallArgs.qll
+++ b/python/ql/src/Expressions/CallArgs.qll
@@ -154,17 +154,21 @@ predicate too_few_args(Call call, Value callable, int limit) {
not exists(call.getKwargs()) and
arg_count(call) < limit and
exists(FunctionValue func | func = get_function_or_initializer(callable) |
- call = func.getAFunctionCall().getNode() and limit = func.minParameters() and
- /* The combination of misuse of `mox.Mox().StubOutWithMock()`
- * and a bug in mox's implementation of methods results in having to
- * pass 1 too few arguments to the mocked function.
- */
- not (useOfMoxInModule(call.getEnclosingModule()) and func.isNormalMethod())
- or
- call = func.getAMethodCall().getNode() and limit = func.minParameters() - 1
- or
- callable instanceof ClassValue and
- call.getAFlowNode() = get_a_call(callable) and limit = func.minParameters() - 1
+ call = func.getAFunctionCall().getNode() and
+ limit = func.minParameters() and
+ /*
+ * The combination of misuse of `mox.Mox().StubOutWithMock()`
+ * and a bug in mox's implementation of methods results in having to
+ * pass 1 too few arguments to the mocked function.
+ */
+
+ not (useOfMoxInModule(call.getEnclosingModule()) and func.isNormalMethod())
+ or
+ call = func.getAMethodCall().getNode() and limit = func.minParameters() - 1
+ or
+ callable instanceof ClassValue and
+ call.getAFlowNode() = get_a_call(callable) and
+ limit = func.minParameters() - 1
)
}
@@ -192,14 +196,15 @@ predicate too_many_args_objectapi(Call call, Object callable, int limit) {
predicate too_many_args(Call call, Value callable, int limit) {
// Exclude cases where an incorrect name is used as that is covered by 'Wrong name for an argument in a call'
not illegally_named_parameter(call, callable, _) and
- exists(FunctionValue func |
- func = get_function_or_initializer(callable) and
- not func.getScope().hasVarArg() and limit >= 0
- |
+ exists(FunctionValue func |
+ func = get_function_or_initializer(callable) and
+ not func.getScope().hasVarArg() and
+ limit >= 0
+ |
call = func.getAFunctionCall().getNode() and limit = func.maxParameters()
- or
+ or
call = func.getAMethodCall().getNode() and limit = func.maxParameters() - 1
- or
+ or
callable instanceof ClassValue and
call.getAFlowNode() = get_a_call(callable) and
limit = func.maxParameters() - 1
From bbe7314c1799f90c76716f2bcec42d0d0b4ac8ac Mon Sep 17 00:00:00 2001
From: Rebecca Valentine
Date: Fri, 3 Apr 2020 20:30:24 -0700
Subject: [PATCH 0058/1298] Python: ObjAPI to ValAPI: WrongNumArgsInCall:
Autoformats ObjectAPI.qll
---
.../src/semmle/python/objects/ObjectAPI.qll | 39 ++++++-------------
1 file changed, 11 insertions(+), 28 deletions(-)
diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll
index 7a8e3080fb9..331bc283594 100644
--- a/python/ql/src/semmle/python/objects/ObjectAPI.qll
+++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll
@@ -614,9 +614,9 @@ class PythonFunctionValue extends FunctionValue {
override string descriptiveString() {
if this.getScope().isMethod()
then
- exists(Class cls | this.getScope().getScope() = cls |
- result = "method " + this.getQualifiedName()
- )
+ exists(Class cls | this.getScope().getScope() = cls |
+ result = "method " + this.getQualifiedName()
+ )
else result = "function " + this.getQualifiedName()
}
@@ -641,14 +641,9 @@ class PythonFunctionValue extends FunctionValue {
}
/** Gets a control flow node corresponding to a return statement in this function */
- ControlFlowNode getAReturnedNode() {
- result = this.getScope().getAReturnValueFlowNode()
- }
-
- override ClassValue getARaisedType() {
- scope_raises(result, this.getScope())
- }
+ ControlFlowNode getAReturnedNode() { result = this.getScope().getAReturnValueFlowNode() }
+ override ClassValue getARaisedType() { scope_raises(result, this.getScope()) }
}
/** Class representing builtin functions, such as `len` or `print` */
@@ -661,9 +656,7 @@ class BuiltinFunctionValue extends FunctionValue {
override int minParameters() { none() }
- override int maxParameters() {
- none()
- }
+ override int maxParameters() { none() }
override ClassValue getARaisedType() {
/* Information is unavailable for C code in general */
@@ -685,19 +678,14 @@ class BuiltinMethodValue extends FunctionValue {
override string descriptiveString() { result = "builtin-method " + this.getQualifiedName() }
- override int minParameters() {
- none()
- }
+ override int minParameters() { none() }
- override int maxParameters() {
- none()
- }
+ override int maxParameters() { none() }
override ClassValue getARaisedType() {
/* Information is unavailable for C code in general */
none()
}
-
}
/**
@@ -923,10 +911,8 @@ module ClassValue {
ClassValue lookupError() { result = TBuiltinClassObject(Builtin::builtin("LookupError")) }
/** Get the `ClassValue` for the `IndexError` class. */
- ClassValue indexError() {
- result = TBuiltinClassObject(Builtin::builtin("IndexError"))
- }
-
+ ClassValue indexError() { result = TBuiltinClassObject(Builtin::builtin("IndexError")) }
+
/** Get the `ClassValue` for the `IOError` class. */
ClassValue ioError() { result = TBuiltinClassObject(Builtin::builtin("IOError")) }
@@ -949,8 +935,5 @@ module ClassValue {
}
/** Get the `ClassValue` for the `SystemExit` class. */
- ClassValue systemExit() {
- result = TBuiltinClassObject(Builtin::builtin("SystemExit"))
- }
-
+ ClassValue systemExit() { result = TBuiltinClassObject(Builtin::builtin("SystemExit")) }
}
From 26bdb9ab04163fc8ec052c8c469e89e4a04a3c77 Mon Sep 17 00:00:00 2001
From: Rebecca Valentine
Date: Fri, 3 Apr 2020 20:33:17 -0700
Subject: [PATCH 0059/1298] Python: ObjAPI to ValAPI: WrongNumArgsInCall:
Exceptions.qll: Removes extraneous spaces in comments
---
python/ql/src/semmle/python/types/Exceptions.qll | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/python/ql/src/semmle/python/types/Exceptions.qll b/python/ql/src/semmle/python/types/Exceptions.qll
index b194807e4a1..7fe1b274664 100644
--- a/python/ql/src/semmle/python/types/Exceptions.qll
+++ b/python/ql/src/semmle/python/types/Exceptions.qll
@@ -34,7 +34,7 @@ class RaisingNode extends ControlFlowNode {
/**
* Gets the type of an exception that may be raised
- * at this control flow node
+ * at this control flow node
*/
ClassObject getARaisedType_objectapi() {
result = this.localRaisedType_objectapi()
@@ -46,7 +46,7 @@ class RaisingNode extends ControlFlowNode {
/**
* Gets the type of an exception that may be raised
- * at this control flow node
+ * at this control flow node
*/
ClassValue getARaisedType() {
result = this.localRaisedType()
From 88be3359ac10c8975bae07cb2087dffdc4330de9 Mon Sep 17 00:00:00 2001
From: Rebecca Valentine
Date: Sat, 4 Apr 2020 00:15:10 -0700
Subject: [PATCH 0060/1298] Python: ObjAPI to ValAPI: WrongNumForArgsInCall:
Update affected queries to use objectapi
---
python/ql/test/library-tests/types/exceptions/ExitRaises.ql | 2 +-
python/ql/test/library-tests/types/exceptions/Handles.ql | 2 +-
python/ql/test/library-tests/types/exceptions/Viable.ql | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/python/ql/test/library-tests/types/exceptions/ExitRaises.ql b/python/ql/test/library-tests/types/exceptions/ExitRaises.ql
index 62be45dce8e..32ef268332c 100644
--- a/python/ql/test/library-tests/types/exceptions/ExitRaises.ql
+++ b/python/ql/test/library-tests/types/exceptions/ExitRaises.ql
@@ -1,5 +1,5 @@
import python
from RaisingNode r, Scope s, ClassObject cls
-where r.viableExceptionalExit(s, cls)
+where r.viableExceptionalExit_objectapi(s, cls)
select r.getLocation().getStartLine(), r, s.toString(), cls
diff --git a/python/ql/test/library-tests/types/exceptions/Handles.ql b/python/ql/test/library-tests/types/exceptions/Handles.ql
index 601f2632392..dfdf1f9d7b2 100644
--- a/python/ql/test/library-tests/types/exceptions/Handles.ql
+++ b/python/ql/test/library-tests/types/exceptions/Handles.ql
@@ -1,5 +1,5 @@
import python
from ExceptFlowNode n, ClassObject cls
-where n.handles(cls)
+where n.handles_objectapi(cls)
select n.getLocation().getStartLine(), cls.toString()
diff --git a/python/ql/test/library-tests/types/exceptions/Viable.ql b/python/ql/test/library-tests/types/exceptions/Viable.ql
index e28fa1a907c..ed388e2faf2 100644
--- a/python/ql/test/library-tests/types/exceptions/Viable.ql
+++ b/python/ql/test/library-tests/types/exceptions/Viable.ql
@@ -1,6 +1,6 @@
import python
from RaisingNode r, ControlFlowNode n, ClassObject ex
-where r.viableExceptionEdge(n, ex)
+where r.viableExceptionEdge_objectapi(n, ex)
select r.getLocation().getStartLine(), n.getLocation().getStartLine(), r.getNode().toString(),
n.getNode().toString(), ex.toString()
From 8c1aeb24cb3b678843455a1e5bbe16755e734894 Mon Sep 17 00:00:00 2001
From: Rebecca Valentine
Date: Sat, 4 Apr 2020 00:57:09 -0700
Subject: [PATCH 0061/1298] Python: ObjAPI to ValAPI: WrongNumArgsInCall:
Updates query expected results
---
.../Arguments/WrongNumberArgumentsInCall.expected | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/python/ql/test/query-tests/Expressions/Arguments/WrongNumberArgumentsInCall.expected b/python/ql/test/query-tests/Expressions/Arguments/WrongNumberArgumentsInCall.expected
index c23418acd45..31adabb9e05 100644
--- a/python/ql/test/query-tests/Expressions/Arguments/WrongNumberArgumentsInCall.expected
+++ b/python/ql/test/query-tests/Expressions/Arguments/WrongNumberArgumentsInCall.expected
@@ -1,7 +1,7 @@
| use_mox.py:28:1:28:4 | f0() | Call to $@ with too few arguments; should be no fewer than 1. | use_mox.py:7:1:7:10 | Function f0 | function f0 |
| use_mox.py:29:1:29:5 | f1() | Call to $@ with too few arguments; should be no fewer than 2. | use_mox.py:10:1:10:13 | Function f1 | function f1 |
-| use_mox.py:32:1:32:8 | Attribute() | Call to $@ with too few arguments; should be no fewer than 1. | use_mox.py:15:5:15:20 | Function m0 | method C.m0 |
-| use_mox.py:33:1:33:9 | Attribute() | Call to $@ with too few arguments; should be no fewer than 2. | use_mox.py:18:5:18:23 | Function m1 | method C.m1 |
+| use_mox.py:32:1:32:8 | Attribute() | Call to $@ with too few arguments; should be no fewer than 1. | use_mox.py:15:5:15:20 | Function C.m0 | method C.m0 |
+| use_mox.py:33:1:33:9 | Attribute() | Call to $@ with too few arguments; should be no fewer than 2. | use_mox.py:18:5:18:23 | Function C.m1 | method C.m1 |
| wrong_arguments.py:29:1:29:4 | f0() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:3:1:3:10 | Function f0 | function f0 |
| wrong_arguments.py:30:1:30:4 | f1() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:6:1:6:20 | Function f1 | function f1 |
| wrong_arguments.py:31:1:31:4 | f2() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:9:1:9:14 | Function f2 | function f2 |
@@ -21,5 +21,5 @@
| wrong_arguments.py:86:1:86:4 | l1() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:71:6:71:21 | Function lambda | function lambda |
| wrong_arguments.py:96:1:96:12 | f6() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:21:1:21:13 | Function f6 | function f6 |
| wrong_arguments.py:97:1:97:7 | f6() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:21:1:21:13 | Function f6 | function f6 |
-| wrong_arguments.py:130:1:130:9 | Attribute() | Call to $@ with too few arguments; should be no fewer than 2. | wrong_arguments.py:126:5:126:31 | Function spam | method Eggs2.spam |
-| wrong_arguments.py:130:1:130:9 | Attribute() | Call to $@ with too many arguments; should be no more than 0. | wrong_arguments.py:121:5:121:19 | Function spam | method Eggs1.spam |
+| wrong_arguments.py:130:1:130:9 | Attribute() | Call to $@ with too few arguments; should be no fewer than 2. | wrong_arguments.py:126:5:126:31 | Function Eggs2.spam | method Eggs2.spam |
+| wrong_arguments.py:130:1:130:9 | Attribute() | Call to $@ with too many arguments; should be no more than 0. | wrong_arguments.py:121:5:121:19 | Function Eggs1.spam | method Eggs1.spam |
From 01aac8273cb7b84fbf21c5bc80e1dd455fb0710d Mon Sep 17 00:00:00 2001
From: Rebecca Valentine
Date: Sat, 4 Apr 2020 03:11:25 -0700
Subject: [PATCH 0062/1298] Python: ObjAPI to ValAPI: WrongNumArgsInCall:
Update queries to use objectapi
---
python/ql/test/2/library-tests/types/exceptions/ExitRaises.ql | 2 +-
python/ql/test/3/library-tests/types/exceptions/Viable.ql | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/python/ql/test/2/library-tests/types/exceptions/ExitRaises.ql b/python/ql/test/2/library-tests/types/exceptions/ExitRaises.ql
index 8e4c47a3e74..415db290a05 100644
--- a/python/ql/test/2/library-tests/types/exceptions/ExitRaises.ql
+++ b/python/ql/test/2/library-tests/types/exceptions/ExitRaises.ql
@@ -1,5 +1,5 @@
import python
from RaisingNode r, Scope s, ClassObject cls
-where r.viableExceptionalExit(s, cls)
+where r.viableExceptionalExit_objectapi(s, cls)
select r.getLocation().getStartLine(), r.toString(), s.toString(), cls.toString()
diff --git a/python/ql/test/3/library-tests/types/exceptions/Viable.ql b/python/ql/test/3/library-tests/types/exceptions/Viable.ql
index e28fa1a907c..ed388e2faf2 100644
--- a/python/ql/test/3/library-tests/types/exceptions/Viable.ql
+++ b/python/ql/test/3/library-tests/types/exceptions/Viable.ql
@@ -1,6 +1,6 @@
import python
from RaisingNode r, ControlFlowNode n, ClassObject ex
-where r.viableExceptionEdge(n, ex)
+where r.viableExceptionEdge_objectapi(n, ex)
select r.getLocation().getStartLine(), n.getLocation().getStartLine(), r.getNode().toString(),
n.getNode().toString(), ex.toString()
From 317734f41e011f73794fa740aaa62843467ae553 Mon Sep 17 00:00:00 2001
From: Mathias Vorreiter Pedersen
Date: Sun, 5 Apr 2020 22:35:26 +0200
Subject: [PATCH 0063/1298] C++: Attach PostUpdateNodes to Chi nodes following
aschackmull's suggestion
---
.../ir/dataflow/internal/DataFlowPrivate.qll | 6 +-
.../cpp/ir/dataflow/internal/DataFlowUtil.qll | 61 +++++++-------
.../dataflow/fields/ir-flow.expected | 80 -------------------
3 files changed, 31 insertions(+), 116 deletions(-)
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
index c80982bd4d5..5d99866e7ea 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
@@ -148,10 +148,10 @@ predicate storeStep(Node node1, Content f, PostUpdateNode node2) {
*/
predicate readStep(Node node1, Content f, Node node2) {
exists(FieldAddressInstruction fa, LoadInstruction load |
- load.getSourceAddress() = fa and
- node1.asInstruction() = fa.getObjectAddress() and
fa.getField() = f.(FieldContent).getField() and
- load = node2.asInstruction()
+ node1.asInstruction() = load and
+ load.getSourceAddress() = fa and
+ node2.asInstruction().getAnOperand().getAnyDef() = load
)
}
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
index 5eba5108983..018901eb946 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
@@ -245,30 +245,19 @@ abstract class PostUpdateNode extends InstructionNode {
* setY(&x); // a partial definition of the object `x`.
* ```
*/
-abstract class PartialDefinitionNode extends PostUpdateNode, TInstructionNode {
- /**
- * Gets the instruction that partially defines the object. This includes
- * both the instruction that partially defines the object, and the chi
- * instruction that links up the partial definition to the object.
- */
- final Instruction getInstructionOrChi() {
- exists(ChiInstruction chi |
- not chi.isResultConflated() and
- chi.getPartial() = getInstruction() and
- result = chi
- )
- or
- result = getInstruction()
- }
-}
+abstract class PartialDefinitionNode extends PostUpdateNode, TInstructionNode {}
private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
- override StoreInstruction instr;
- FieldAddressInstruction field;
+ override ChiInstruction instr;
- ExplicitFieldStoreQualifierNode() { field = instr.getDestinationAddress() }
+ ExplicitFieldStoreQualifierNode() {
+ not instr.isResultConflated() and
+ exists(StoreInstruction store, FieldInstruction field |
+ instr.getPartial() = store and field = store.getDestinationAddress()
+ )
+ }
- override Node getPreUpdateNode() { result.asInstruction() = field.getObjectAddress() }
+ override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() }
}
/**
@@ -282,29 +271,29 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
* `getVariableAccess()` equal to `x`.
*/
class DefinitionByReferenceNode extends PartialDefinitionNode {
- override WriteSideEffectInstruction instr;
+ override ChiInstruction instr;
+ WriteSideEffectInstruction write;
CallInstruction call;
- DefinitionByReferenceNode() { call = instr.getPrimaryInstruction() }
+ DefinitionByReferenceNode() {
+ instr.getPartial() = write and
+ call = write.getPrimaryInstruction() }
override Node getPreUpdateNode() {
- result.asInstruction() = call.getPositionalArgument(instr.getIndex())
- or
- result.asInstruction() = call.getThisArgument() and
- instr.getIndex() = -1
+ result.asInstruction() = instr.getTotal()
}
/** Gets the argument corresponding to this node. */
Expr getArgument() {
- result = call.getPositionalArgument(instr.getIndex()).getUnconvertedResultExpression()
+ result = call.getPositionalArgument(write.getIndex()).getUnconvertedResultExpression()
or
result = call.getThisArgument().getUnconvertedResultExpression() and
- instr.getIndex() = -1
+ write.getIndex() = -1
}
/** Gets the parameter through which this value is assigned. */
Parameter getParameter() {
- exists(CallInstruction ci | result = ci.getStaticCallTarget().getParameter(instr.getIndex()))
+ exists(CallInstruction ci | result = ci.getStaticCallTarget().getParameter(write.getIndex()))
}
}
@@ -393,10 +382,10 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction())
or
- exists(LoadInstruction load |
- load.getSourceValueOperand().getAnyDef() =
- nodeFrom.(PartialDefinitionNode).getInstructionOrChi() and
- nodeTo.asInstruction() = load.getSourceAddress().(FieldAddressInstruction).getObjectAddress()
+ exists(LoadInstruction load, ChiInstruction chi |
+ nodeTo.asInstruction() = load and
+ nodeFrom.asInstruction() = chi and
+ load.getSourceValueOperand().getAnyDef() = chi
)
}
@@ -423,6 +412,12 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction
//
// Flow through the partial operand belongs in the taint-tracking libraries
// for now.
+
+ // TODO: To capture flow from a partial definition of an object (i.e., a field write) to the object
+ // we add dataflow through partial chi operands, but only if the chi node is not the chi node for all
+ // aliased memory.
+ iTo.getAnOperand().(ChiPartialOperand).getDef() = iFrom and not iFrom.isResultConflated()
+ or
iTo.getAnOperand().(ChiTotalOperand).getDef() = iFrom
or
// Flow through modeled functions
diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
index 3c7bbe96a7d..2503be80b00 100644
--- a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
+++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
@@ -1,107 +1,27 @@
edges
-| aliasing.cpp:9:3:9:22 | Store : void | aliasing.cpp:9:3:9:22 | Store [m1] : void |
-| aliasing.cpp:9:3:9:22 | Store [m1] : void | aliasing.cpp:25:17:25:19 | BufferMayWriteSideEffect [m1] : void |
-| aliasing.cpp:9:11:9:20 | call to user_input : void | aliasing.cpp:9:3:9:22 | Store : void |
-| aliasing.cpp:13:3:13:21 | Store : void | aliasing.cpp:13:3:13:21 | Store [m1] : void |
-| aliasing.cpp:13:3:13:21 | Store [m1] : void | aliasing.cpp:26:19:26:20 | BufferMayWriteSideEffect [m1] : void |
-| aliasing.cpp:13:10:13:19 | call to user_input : void | aliasing.cpp:13:3:13:21 | Store : void |
-| aliasing.cpp:25:17:25:19 | BufferMayWriteSideEffect [m1] : void | aliasing.cpp:29:8:29:9 | s1 [m1] : void |
-| aliasing.cpp:26:19:26:20 | BufferMayWriteSideEffect [m1] : void | aliasing.cpp:30:8:30:9 | s2 [m1] : void |
-| aliasing.cpp:29:8:29:9 | s1 [m1] : void | aliasing.cpp:29:11:29:12 | m1 |
-| aliasing.cpp:30:8:30:9 | s2 [m1] : void | aliasing.cpp:30:11:30:12 | m1 |
-| aliasing.cpp:37:3:37:24 | Store : void | aliasing.cpp:37:3:37:24 | Store [m1] : void |
-| aliasing.cpp:37:3:37:24 | Store : void | aliasing.cpp:38:11:38:12 | m1 |
-| aliasing.cpp:37:3:37:24 | Store [m1] : void | aliasing.cpp:38:8:38:9 | s1 [m1] : void |
-| aliasing.cpp:37:13:37:22 | call to user_input : void | aliasing.cpp:37:3:37:24 | Store : void |
| aliasing.cpp:37:13:37:22 | call to user_input : void | aliasing.cpp:38:11:38:12 | m1 |
-| aliasing.cpp:38:8:38:9 | s1 [m1] : void | aliasing.cpp:38:11:38:12 | m1 |
-| aliasing.cpp:42:3:42:22 | Store : void | aliasing.cpp:42:3:42:22 | Store [m1] : void |
-| aliasing.cpp:42:3:42:22 | Store : void | aliasing.cpp:43:13:43:14 | m1 |
-| aliasing.cpp:42:3:42:22 | Store [m1] : void | aliasing.cpp:43:8:43:11 | (reference dereference) [m1] : void |
-| aliasing.cpp:42:11:42:20 | call to user_input : void | aliasing.cpp:42:3:42:22 | Store : void |
| aliasing.cpp:42:11:42:20 | call to user_input : void | aliasing.cpp:43:13:43:14 | m1 |
-| aliasing.cpp:43:8:43:11 | (reference dereference) [m1] : void | aliasing.cpp:43:13:43:14 | m1 |
-| aliasing.cpp:79:3:79:22 | Store : void | aliasing.cpp:79:3:79:22 | Store [m1] : void |
-| aliasing.cpp:79:3:79:22 | Store : void | aliasing.cpp:80:12:80:13 | m1 |
-| aliasing.cpp:79:3:79:22 | Store [m1] : void | aliasing.cpp:80:10:80:10 | s [m1] : void |
-| aliasing.cpp:79:11:79:20 | call to user_input : void | aliasing.cpp:79:3:79:22 | Store : void |
| aliasing.cpp:79:11:79:20 | call to user_input : void | aliasing.cpp:80:12:80:13 | m1 |
-| aliasing.cpp:80:10:80:10 | s [m1] : void | aliasing.cpp:80:12:80:13 | m1 |
-| aliasing.cpp:86:3:86:21 | Store : void | aliasing.cpp:86:3:86:21 | Store [m1] : void |
-| aliasing.cpp:86:3:86:21 | Store : void | aliasing.cpp:87:12:87:13 | m1 |
-| aliasing.cpp:86:3:86:21 | Store [m1] : void | aliasing.cpp:87:10:87:10 | s [m1] : void |
-| aliasing.cpp:86:10:86:19 | call to user_input : void | aliasing.cpp:86:3:86:21 | Store : void |
| aliasing.cpp:86:10:86:19 | call to user_input : void | aliasing.cpp:87:12:87:13 | m1 |
-| aliasing.cpp:87:10:87:10 | s [m1] : void | aliasing.cpp:87:12:87:13 | m1 |
-| aliasing.cpp:92:3:92:23 | Store : void | aliasing.cpp:92:3:92:23 | Store [m1] : void |
-| aliasing.cpp:92:3:92:23 | Store : void | aliasing.cpp:93:12:93:13 | m1 |
-| aliasing.cpp:92:3:92:23 | Store [m1] : void | aliasing.cpp:93:10:93:10 | s [m1] : void |
-| aliasing.cpp:92:12:92:21 | call to user_input : void | aliasing.cpp:92:3:92:23 | Store : void |
| aliasing.cpp:92:12:92:21 | call to user_input : void | aliasing.cpp:93:12:93:13 | m1 |
-| aliasing.cpp:93:10:93:10 | s [m1] : void | aliasing.cpp:93:12:93:13 | m1 |
-| struct_init.c:20:20:20:29 | Store : void | struct_init.c:20:20:20:29 | Store [a] : void |
-| struct_init.c:20:20:20:29 | Store : void | struct_init.c:22:11:22:11 | a |
-| struct_init.c:20:20:20:29 | Store [a] : void | struct_init.c:22:8:22:9 | ab [a] : void |
-| struct_init.c:20:20:20:29 | call to user_input : void | struct_init.c:20:20:20:29 | Store : void |
| struct_init.c:20:20:20:29 | call to user_input : void | struct_init.c:22:11:22:11 | a |
-| struct_init.c:22:8:22:9 | ab [a] : void | struct_init.c:22:11:22:11 | a |
-| struct_init.c:27:7:27:16 | Store : void | struct_init.c:27:7:27:16 | Store [a] : void |
-| struct_init.c:27:7:27:16 | Store : void | struct_init.c:31:23:31:23 | a |
-| struct_init.c:27:7:27:16 | Store [a] : void | struct_init.c:31:14:31:21 | nestedAB [a] : void |
-| struct_init.c:27:7:27:16 | call to user_input : void | struct_init.c:27:7:27:16 | Store : void |
| struct_init.c:27:7:27:16 | call to user_input : void | struct_init.c:31:23:31:23 | a |
-| struct_init.c:31:14:31:21 | nestedAB [a] : void | struct_init.c:31:23:31:23 | a |
nodes
-| aliasing.cpp:9:3:9:22 | Store : void | semmle.label | Store : void |
-| aliasing.cpp:9:3:9:22 | Store [m1] : void | semmle.label | Store [m1] : void |
-| aliasing.cpp:9:11:9:20 | call to user_input : void | semmle.label | call to user_input : void |
-| aliasing.cpp:13:3:13:21 | Store : void | semmle.label | Store : void |
-| aliasing.cpp:13:3:13:21 | Store [m1] : void | semmle.label | Store [m1] : void |
-| aliasing.cpp:13:10:13:19 | call to user_input : void | semmle.label | call to user_input : void |
-| aliasing.cpp:25:17:25:19 | BufferMayWriteSideEffect [m1] : void | semmle.label | BufferMayWriteSideEffect [m1] : void |
-| aliasing.cpp:26:19:26:20 | BufferMayWriteSideEffect [m1] : void | semmle.label | BufferMayWriteSideEffect [m1] : void |
-| aliasing.cpp:29:8:29:9 | s1 [m1] : void | semmle.label | s1 [m1] : void |
-| aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 |
-| aliasing.cpp:30:8:30:9 | s2 [m1] : void | semmle.label | s2 [m1] : void |
-| aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 |
-| aliasing.cpp:37:3:37:24 | Store : void | semmle.label | Store : void |
-| aliasing.cpp:37:3:37:24 | Store [m1] : void | semmle.label | Store [m1] : void |
| aliasing.cpp:37:13:37:22 | call to user_input : void | semmle.label | call to user_input : void |
-| aliasing.cpp:38:8:38:9 | s1 [m1] : void | semmle.label | s1 [m1] : void |
| aliasing.cpp:38:11:38:12 | m1 | semmle.label | m1 |
-| aliasing.cpp:42:3:42:22 | Store : void | semmle.label | Store : void |
-| aliasing.cpp:42:3:42:22 | Store [m1] : void | semmle.label | Store [m1] : void |
| aliasing.cpp:42:11:42:20 | call to user_input : void | semmle.label | call to user_input : void |
-| aliasing.cpp:43:8:43:11 | (reference dereference) [m1] : void | semmle.label | (reference dereference) [m1] : void |
| aliasing.cpp:43:13:43:14 | m1 | semmle.label | m1 |
-| aliasing.cpp:79:3:79:22 | Store : void | semmle.label | Store : void |
-| aliasing.cpp:79:3:79:22 | Store [m1] : void | semmle.label | Store [m1] : void |
| aliasing.cpp:79:11:79:20 | call to user_input : void | semmle.label | call to user_input : void |
-| aliasing.cpp:80:10:80:10 | s [m1] : void | semmle.label | s [m1] : void |
| aliasing.cpp:80:12:80:13 | m1 | semmle.label | m1 |
-| aliasing.cpp:86:3:86:21 | Store : void | semmle.label | Store : void |
-| aliasing.cpp:86:3:86:21 | Store [m1] : void | semmle.label | Store [m1] : void |
| aliasing.cpp:86:10:86:19 | call to user_input : void | semmle.label | call to user_input : void |
-| aliasing.cpp:87:10:87:10 | s [m1] : void | semmle.label | s [m1] : void |
| aliasing.cpp:87:12:87:13 | m1 | semmle.label | m1 |
-| aliasing.cpp:92:3:92:23 | Store : void | semmle.label | Store : void |
-| aliasing.cpp:92:3:92:23 | Store [m1] : void | semmle.label | Store [m1] : void |
| aliasing.cpp:92:12:92:21 | call to user_input : void | semmle.label | call to user_input : void |
-| aliasing.cpp:93:10:93:10 | s [m1] : void | semmle.label | s [m1] : void |
| aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 |
-| struct_init.c:20:20:20:29 | Store : void | semmle.label | Store : void |
-| struct_init.c:20:20:20:29 | Store [a] : void | semmle.label | Store [a] : void |
| struct_init.c:20:20:20:29 | call to user_input : void | semmle.label | call to user_input : void |
-| struct_init.c:22:8:22:9 | ab [a] : void | semmle.label | ab [a] : void |
| struct_init.c:22:11:22:11 | a | semmle.label | a |
-| struct_init.c:27:7:27:16 | Store : void | semmle.label | Store : void |
-| struct_init.c:27:7:27:16 | Store [a] : void | semmle.label | Store [a] : void |
| struct_init.c:27:7:27:16 | call to user_input : void | semmle.label | call to user_input : void |
-| struct_init.c:31:14:31:21 | nestedAB [a] : void | semmle.label | nestedAB [a] : void |
| struct_init.c:31:23:31:23 | a | semmle.label | a |
#select
-| aliasing.cpp:29:11:29:12 | m1 | aliasing.cpp:9:11:9:20 | call to user_input : void | aliasing.cpp:29:11:29:12 | m1 | m1 flows from $@ | aliasing.cpp:9:11:9:20 | call to user_input : void | call to user_input : void |
-| aliasing.cpp:30:11:30:12 | m1 | aliasing.cpp:13:10:13:19 | call to user_input : void | aliasing.cpp:30:11:30:12 | m1 | m1 flows from $@ | aliasing.cpp:13:10:13:19 | call to user_input : void | call to user_input : void |
| aliasing.cpp:38:11:38:12 | m1 | aliasing.cpp:37:13:37:22 | call to user_input : void | aliasing.cpp:38:11:38:12 | m1 | m1 flows from $@ | aliasing.cpp:37:13:37:22 | call to user_input : void | call to user_input : void |
| aliasing.cpp:43:13:43:14 | m1 | aliasing.cpp:42:11:42:20 | call to user_input : void | aliasing.cpp:43:13:43:14 | m1 | m1 flows from $@ | aliasing.cpp:42:11:42:20 | call to user_input : void | call to user_input : void |
| aliasing.cpp:80:12:80:13 | m1 | aliasing.cpp:79:11:79:20 | call to user_input : void | aliasing.cpp:80:12:80:13 | m1 | m1 flows from $@ | aliasing.cpp:79:11:79:20 | call to user_input : void | call to user_input : void |
From 46fc91315be45c5d290cd9ea6c576e814be9cc7a Mon Sep 17 00:00:00 2001
From: Jonas Jensen
Date: Mon, 6 Apr 2020 08:51:03 +0200
Subject: [PATCH 0064/1298] Java/C++/C#: Revert the join order fix from #2872
This revert brings back the performance problems in
`DataFlowImplLocal.qll` so they can be fixed in a different way. The fix
in #2872 was asymptotically good but had undesired overhead because it
introduced another predicate in the SCC that existed purely for join
ordering.
I did the revert by inlining the helper predicate, eliminating the
`enclosing` variable, and re-ordering the resulting lines to what they
were before #2872.
---
.../cpp/dataflow/internal/DataFlowImpl.qll | 27 +++++--------------
.../cpp/dataflow/internal/DataFlowImpl2.qll | 27 +++++--------------
.../cpp/dataflow/internal/DataFlowImpl3.qll | 27 +++++--------------
.../cpp/dataflow/internal/DataFlowImpl4.qll | 27 +++++--------------
.../dataflow/internal/DataFlowImplLocal.qll | 27 +++++--------------
.../cpp/ir/dataflow/internal/DataFlowImpl.qll | 27 +++++--------------
.../ir/dataflow/internal/DataFlowImpl2.qll | 27 +++++--------------
.../ir/dataflow/internal/DataFlowImpl3.qll | 27 +++++--------------
.../ir/dataflow/internal/DataFlowImpl4.qll | 27 +++++--------------
.../csharp/dataflow/internal/DataFlowImpl.qll | 27 +++++--------------
.../dataflow/internal/DataFlowImpl2.qll | 27 +++++--------------
.../dataflow/internal/DataFlowImpl3.qll | 27 +++++--------------
.../dataflow/internal/DataFlowImpl4.qll | 27 +++++--------------
.../dataflow/internal/DataFlowImpl5.qll | 27 +++++--------------
.../java/dataflow/internal/DataFlowImpl.qll | 27 +++++--------------
.../java/dataflow/internal/DataFlowImpl2.qll | 27 +++++--------------
.../java/dataflow/internal/DataFlowImpl3.qll | 27 +++++--------------
.../java/dataflow/internal/DataFlowImpl4.qll | 27 +++++--------------
.../java/dataflow/internal/DataFlowImpl5.qll | 27 +++++--------------
19 files changed, 133 insertions(+), 380 deletions(-)
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll
index a1daeb66411..ae012897819 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll
@@ -2293,12 +2293,13 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(
- AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
- LocalCallContext localCC
- |
- pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
- localCC = getLocalCallContext(cc, enclosing)
+ exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNode() and
+ conf = mid.getConfiguration() and
+ cc = mid.getCallContext() and
+ sc = mid.getSummaryCtx() and
+ localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
+ ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
@@ -2331,20 +2332,6 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
}
-pragma[nomagic]
-private predicate pathIntoLocalStep(
- PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
- AccessPath ap0, Configuration conf
-) {
- midnode = mid.getNode() and
- cc = mid.getCallContext() and
- conf = mid.getConfiguration() and
- localFlowBigStep(midnode, _, _, _, conf, _) and
- enclosing = midnode.getEnclosingCallable() and
- sc = mid.getSummaryCtx() and
- ap0 = mid.getAp()
-}
-
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll
index a1daeb66411..ae012897819 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll
@@ -2293,12 +2293,13 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(
- AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
- LocalCallContext localCC
- |
- pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
- localCC = getLocalCallContext(cc, enclosing)
+ exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNode() and
+ conf = mid.getConfiguration() and
+ cc = mid.getCallContext() and
+ sc = mid.getSummaryCtx() and
+ localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
+ ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
@@ -2331,20 +2332,6 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
}
-pragma[nomagic]
-private predicate pathIntoLocalStep(
- PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
- AccessPath ap0, Configuration conf
-) {
- midnode = mid.getNode() and
- cc = mid.getCallContext() and
- conf = mid.getConfiguration() and
- localFlowBigStep(midnode, _, _, _, conf, _) and
- enclosing = midnode.getEnclosingCallable() and
- sc = mid.getSummaryCtx() and
- ap0 = mid.getAp()
-}
-
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll
index a1daeb66411..ae012897819 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll
@@ -2293,12 +2293,13 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(
- AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
- LocalCallContext localCC
- |
- pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
- localCC = getLocalCallContext(cc, enclosing)
+ exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNode() and
+ conf = mid.getConfiguration() and
+ cc = mid.getCallContext() and
+ sc = mid.getSummaryCtx() and
+ localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
+ ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
@@ -2331,20 +2332,6 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
}
-pragma[nomagic]
-private predicate pathIntoLocalStep(
- PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
- AccessPath ap0, Configuration conf
-) {
- midnode = mid.getNode() and
- cc = mid.getCallContext() and
- conf = mid.getConfiguration() and
- localFlowBigStep(midnode, _, _, _, conf, _) and
- enclosing = midnode.getEnclosingCallable() and
- sc = mid.getSummaryCtx() and
- ap0 = mid.getAp()
-}
-
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll
index a1daeb66411..ae012897819 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll
@@ -2293,12 +2293,13 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(
- AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
- LocalCallContext localCC
- |
- pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
- localCC = getLocalCallContext(cc, enclosing)
+ exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNode() and
+ conf = mid.getConfiguration() and
+ cc = mid.getCallContext() and
+ sc = mid.getSummaryCtx() and
+ localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
+ ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
@@ -2331,20 +2332,6 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
}
-pragma[nomagic]
-private predicate pathIntoLocalStep(
- PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
- AccessPath ap0, Configuration conf
-) {
- midnode = mid.getNode() and
- cc = mid.getCallContext() and
- conf = mid.getConfiguration() and
- localFlowBigStep(midnode, _, _, _, conf, _) and
- enclosing = midnode.getEnclosingCallable() and
- sc = mid.getSummaryCtx() and
- ap0 = mid.getAp()
-}
-
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll
index a1daeb66411..ae012897819 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll
@@ -2293,12 +2293,13 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(
- AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
- LocalCallContext localCC
- |
- pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
- localCC = getLocalCallContext(cc, enclosing)
+ exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNode() and
+ conf = mid.getConfiguration() and
+ cc = mid.getCallContext() and
+ sc = mid.getSummaryCtx() and
+ localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
+ ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
@@ -2331,20 +2332,6 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
}
-pragma[nomagic]
-private predicate pathIntoLocalStep(
- PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
- AccessPath ap0, Configuration conf
-) {
- midnode = mid.getNode() and
- cc = mid.getCallContext() and
- conf = mid.getConfiguration() and
- localFlowBigStep(midnode, _, _, _, conf, _) and
- enclosing = midnode.getEnclosingCallable() and
- sc = mid.getSummaryCtx() and
- ap0 = mid.getAp()
-}
-
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll
index a1daeb66411..ae012897819 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll
@@ -2293,12 +2293,13 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(
- AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
- LocalCallContext localCC
- |
- pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
- localCC = getLocalCallContext(cc, enclosing)
+ exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNode() and
+ conf = mid.getConfiguration() and
+ cc = mid.getCallContext() and
+ sc = mid.getSummaryCtx() and
+ localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
+ ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
@@ -2331,20 +2332,6 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
}
-pragma[nomagic]
-private predicate pathIntoLocalStep(
- PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
- AccessPath ap0, Configuration conf
-) {
- midnode = mid.getNode() and
- cc = mid.getCallContext() and
- conf = mid.getConfiguration() and
- localFlowBigStep(midnode, _, _, _, conf, _) and
- enclosing = midnode.getEnclosingCallable() and
- sc = mid.getSummaryCtx() and
- ap0 = mid.getAp()
-}
-
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll
index a1daeb66411..ae012897819 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll
@@ -2293,12 +2293,13 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(
- AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
- LocalCallContext localCC
- |
- pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
- localCC = getLocalCallContext(cc, enclosing)
+ exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNode() and
+ conf = mid.getConfiguration() and
+ cc = mid.getCallContext() and
+ sc = mid.getSummaryCtx() and
+ localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
+ ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
@@ -2331,20 +2332,6 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
}
-pragma[nomagic]
-private predicate pathIntoLocalStep(
- PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
- AccessPath ap0, Configuration conf
-) {
- midnode = mid.getNode() and
- cc = mid.getCallContext() and
- conf = mid.getConfiguration() and
- localFlowBigStep(midnode, _, _, _, conf, _) and
- enclosing = midnode.getEnclosingCallable() and
- sc = mid.getSummaryCtx() and
- ap0 = mid.getAp()
-}
-
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll
index a1daeb66411..ae012897819 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll
@@ -2293,12 +2293,13 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(
- AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
- LocalCallContext localCC
- |
- pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
- localCC = getLocalCallContext(cc, enclosing)
+ exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNode() and
+ conf = mid.getConfiguration() and
+ cc = mid.getCallContext() and
+ sc = mid.getSummaryCtx() and
+ localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
+ ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
@@ -2331,20 +2332,6 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
}
-pragma[nomagic]
-private predicate pathIntoLocalStep(
- PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
- AccessPath ap0, Configuration conf
-) {
- midnode = mid.getNode() and
- cc = mid.getCallContext() and
- conf = mid.getConfiguration() and
- localFlowBigStep(midnode, _, _, _, conf, _) and
- enclosing = midnode.getEnclosingCallable() and
- sc = mid.getSummaryCtx() and
- ap0 = mid.getAp()
-}
-
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll
index a1daeb66411..ae012897819 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll
@@ -2293,12 +2293,13 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(
- AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
- LocalCallContext localCC
- |
- pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
- localCC = getLocalCallContext(cc, enclosing)
+ exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNode() and
+ conf = mid.getConfiguration() and
+ cc = mid.getCallContext() and
+ sc = mid.getSummaryCtx() and
+ localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
+ ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
@@ -2331,20 +2332,6 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
}
-pragma[nomagic]
-private predicate pathIntoLocalStep(
- PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
- AccessPath ap0, Configuration conf
-) {
- midnode = mid.getNode() and
- cc = mid.getCallContext() and
- conf = mid.getConfiguration() and
- localFlowBigStep(midnode, _, _, _, conf, _) and
- enclosing = midnode.getEnclosingCallable() and
- sc = mid.getSummaryCtx() and
- ap0 = mid.getAp()
-}
-
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll
index a1daeb66411..ae012897819 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll
@@ -2293,12 +2293,13 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(
- AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
- LocalCallContext localCC
- |
- pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
- localCC = getLocalCallContext(cc, enclosing)
+ exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNode() and
+ conf = mid.getConfiguration() and
+ cc = mid.getCallContext() and
+ sc = mid.getSummaryCtx() and
+ localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
+ ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
@@ -2331,20 +2332,6 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
}
-pragma[nomagic]
-private predicate pathIntoLocalStep(
- PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
- AccessPath ap0, Configuration conf
-) {
- midnode = mid.getNode() and
- cc = mid.getCallContext() and
- conf = mid.getConfiguration() and
- localFlowBigStep(midnode, _, _, _, conf, _) and
- enclosing = midnode.getEnclosingCallable() and
- sc = mid.getSummaryCtx() and
- ap0 = mid.getAp()
-}
-
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll
index a1daeb66411..ae012897819 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll
@@ -2293,12 +2293,13 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(
- AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
- LocalCallContext localCC
- |
- pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
- localCC = getLocalCallContext(cc, enclosing)
+ exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNode() and
+ conf = mid.getConfiguration() and
+ cc = mid.getCallContext() and
+ sc = mid.getSummaryCtx() and
+ localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
+ ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
@@ -2331,20 +2332,6 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
}
-pragma[nomagic]
-private predicate pathIntoLocalStep(
- PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
- AccessPath ap0, Configuration conf
-) {
- midnode = mid.getNode() and
- cc = mid.getCallContext() and
- conf = mid.getConfiguration() and
- localFlowBigStep(midnode, _, _, _, conf, _) and
- enclosing = midnode.getEnclosingCallable() and
- sc = mid.getSummaryCtx() and
- ap0 = mid.getAp()
-}
-
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll
index a1daeb66411..ae012897819 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll
@@ -2293,12 +2293,13 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(
- AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
- LocalCallContext localCC
- |
- pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
- localCC = getLocalCallContext(cc, enclosing)
+ exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNode() and
+ conf = mid.getConfiguration() and
+ cc = mid.getCallContext() and
+ sc = mid.getSummaryCtx() and
+ localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
+ ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
@@ -2331,20 +2332,6 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
}
-pragma[nomagic]
-private predicate pathIntoLocalStep(
- PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
- AccessPath ap0, Configuration conf
-) {
- midnode = mid.getNode() and
- cc = mid.getCallContext() and
- conf = mid.getConfiguration() and
- localFlowBigStep(midnode, _, _, _, conf, _) and
- enclosing = midnode.getEnclosingCallable() and
- sc = mid.getSummaryCtx() and
- ap0 = mid.getAp()
-}
-
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll
index a1daeb66411..ae012897819 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll
@@ -2293,12 +2293,13 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(
- AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
- LocalCallContext localCC
- |
- pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
- localCC = getLocalCallContext(cc, enclosing)
+ exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNode() and
+ conf = mid.getConfiguration() and
+ cc = mid.getCallContext() and
+ sc = mid.getSummaryCtx() and
+ localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
+ ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
@@ -2331,20 +2332,6 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
}
-pragma[nomagic]
-private predicate pathIntoLocalStep(
- PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
- AccessPath ap0, Configuration conf
-) {
- midnode = mid.getNode() and
- cc = mid.getCallContext() and
- conf = mid.getConfiguration() and
- localFlowBigStep(midnode, _, _, _, conf, _) and
- enclosing = midnode.getEnclosingCallable() and
- sc = mid.getSummaryCtx() and
- ap0 = mid.getAp()
-}
-
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll
index a1daeb66411..ae012897819 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll
@@ -2293,12 +2293,13 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(
- AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
- LocalCallContext localCC
- |
- pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
- localCC = getLocalCallContext(cc, enclosing)
+ exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNode() and
+ conf = mid.getConfiguration() and
+ cc = mid.getCallContext() and
+ sc = mid.getSummaryCtx() and
+ localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
+ ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
@@ -2331,20 +2332,6 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
}
-pragma[nomagic]
-private predicate pathIntoLocalStep(
- PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
- AccessPath ap0, Configuration conf
-) {
- midnode = mid.getNode() and
- cc = mid.getCallContext() and
- conf = mid.getConfiguration() and
- localFlowBigStep(midnode, _, _, _, conf, _) and
- enclosing = midnode.getEnclosingCallable() and
- sc = mid.getSummaryCtx() and
- ap0 = mid.getAp()
-}
-
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and
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 a1daeb66411..ae012897819 100644
--- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll
+++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll
@@ -2293,12 +2293,13 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(
- AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
- LocalCallContext localCC
- |
- pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
- localCC = getLocalCallContext(cc, enclosing)
+ exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNode() and
+ conf = mid.getConfiguration() and
+ cc = mid.getCallContext() and
+ sc = mid.getSummaryCtx() and
+ localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
+ ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
@@ -2331,20 +2332,6 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
}
-pragma[nomagic]
-private predicate pathIntoLocalStep(
- PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
- AccessPath ap0, Configuration conf
-) {
- midnode = mid.getNode() and
- cc = mid.getCallContext() and
- conf = mid.getConfiguration() and
- localFlowBigStep(midnode, _, _, _, conf, _) and
- enclosing = midnode.getEnclosingCallable() and
- sc = mid.getSummaryCtx() and
- ap0 = mid.getAp()
-}
-
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) 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 a1daeb66411..ae012897819 100644
--- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll
+++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll
@@ -2293,12 +2293,13 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(
- AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
- LocalCallContext localCC
- |
- pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
- localCC = getLocalCallContext(cc, enclosing)
+ exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNode() and
+ conf = mid.getConfiguration() and
+ cc = mid.getCallContext() and
+ sc = mid.getSummaryCtx() and
+ localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
+ ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
@@ -2331,20 +2332,6 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
}
-pragma[nomagic]
-private predicate pathIntoLocalStep(
- PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
- AccessPath ap0, Configuration conf
-) {
- midnode = mid.getNode() and
- cc = mid.getCallContext() and
- conf = mid.getConfiguration() and
- localFlowBigStep(midnode, _, _, _, conf, _) and
- enclosing = midnode.getEnclosingCallable() and
- sc = mid.getSummaryCtx() and
- ap0 = mid.getAp()
-}
-
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) 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 a1daeb66411..ae012897819 100644
--- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll
+++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll
@@ -2293,12 +2293,13 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(
- AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
- LocalCallContext localCC
- |
- pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
- localCC = getLocalCallContext(cc, enclosing)
+ exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNode() and
+ conf = mid.getConfiguration() and
+ cc = mid.getCallContext() and
+ sc = mid.getSummaryCtx() and
+ localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
+ ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
@@ -2331,20 +2332,6 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
}
-pragma[nomagic]
-private predicate pathIntoLocalStep(
- PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
- AccessPath ap0, Configuration conf
-) {
- midnode = mid.getNode() and
- cc = mid.getCallContext() and
- conf = mid.getConfiguration() and
- localFlowBigStep(midnode, _, _, _, conf, _) and
- enclosing = midnode.getEnclosingCallable() and
- sc = mid.getSummaryCtx() and
- ap0 = mid.getAp()
-}
-
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) 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 a1daeb66411..ae012897819 100644
--- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll
+++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll
@@ -2293,12 +2293,13 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(
- AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
- LocalCallContext localCC
- |
- pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
- localCC = getLocalCallContext(cc, enclosing)
+ exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNode() and
+ conf = mid.getConfiguration() and
+ cc = mid.getCallContext() and
+ sc = mid.getSummaryCtx() and
+ localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
+ ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
@@ -2331,20 +2332,6 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
}
-pragma[nomagic]
-private predicate pathIntoLocalStep(
- PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
- AccessPath ap0, Configuration conf
-) {
- midnode = mid.getNode() and
- cc = mid.getCallContext() and
- conf = mid.getConfiguration() and
- localFlowBigStep(midnode, _, _, _, conf, _) and
- enclosing = midnode.getEnclosingCallable() and
- sc = mid.getSummaryCtx() and
- ap0 = mid.getAp()
-}
-
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) 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 a1daeb66411..ae012897819 100644
--- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll
+++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll
@@ -2293,12 +2293,13 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
- exists(
- AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
- LocalCallContext localCC
- |
- pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
- localCC = getLocalCallContext(cc, enclosing)
+ exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC |
+ midnode = mid.getNode() and
+ conf = mid.getConfiguration() and
+ cc = mid.getCallContext() and
+ sc = mid.getSummaryCtx() and
+ localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
+ ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
@@ -2331,20 +2332,6 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
}
-pragma[nomagic]
-private predicate pathIntoLocalStep(
- PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
- AccessPath ap0, Configuration conf
-) {
- midnode = mid.getNode() and
- cc = mid.getCallContext() and
- conf = mid.getConfiguration() and
- localFlowBigStep(midnode, _, _, _, conf, _) and
- enclosing = midnode.getEnclosingCallable() and
- sc = mid.getSummaryCtx() and
- ap0 = mid.getAp()
-}
-
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and
From 3aa293210d05cb5a52c60515cf018f87e836bb9b Mon Sep 17 00:00:00 2001
From: Mathias Vorreiter Pedersen
Date: Mon, 6 Apr 2020 12:02:56 +0200
Subject: [PATCH 0065/1298] C++: Ensure that only non-conflated chi
instructions are used everywhere
---
.../cpp/ir/dataflow/internal/DataFlowUtil.qll | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
index 018901eb946..49ff9a85ad5 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
@@ -245,7 +245,7 @@ abstract class PostUpdateNode extends InstructionNode {
* setY(&x); // a partial definition of the object `x`.
* ```
*/
-abstract class PartialDefinitionNode extends PostUpdateNode, TInstructionNode {}
+abstract class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { }
private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
override ChiInstruction instr;
@@ -276,13 +276,13 @@ class DefinitionByReferenceNode extends PartialDefinitionNode {
CallInstruction call;
DefinitionByReferenceNode() {
+ not instr.isResultConflated() and
instr.getPartial() = write and
- call = write.getPrimaryInstruction() }
-
- override Node getPreUpdateNode() {
- result.asInstruction() = instr.getTotal()
+ call = write.getPrimaryInstruction()
}
+ override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() }
+
/** Gets the argument corresponding to this node. */
Expr getArgument() {
result = call.getPositionalArgument(write.getIndex()).getUnconvertedResultExpression()
@@ -292,9 +292,7 @@ class DefinitionByReferenceNode extends PartialDefinitionNode {
}
/** Gets the parameter through which this value is assigned. */
- Parameter getParameter() {
- exists(CallInstruction ci | result = ci.getStaticCallTarget().getParameter(write.getIndex()))
- }
+ Parameter getParameter() { result = call.getStaticCallTarget().getParameter(write.getIndex()) }
}
/**
@@ -383,6 +381,7 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction())
or
exists(LoadInstruction load, ChiInstruction chi |
+ not chi.isResultConflated() and
nodeTo.asInstruction() = load and
nodeFrom.asInstruction() = chi and
load.getSourceValueOperand().getAnyDef() = chi
@@ -412,11 +411,10 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction
//
// Flow through the partial operand belongs in the taint-tracking libraries
// for now.
-
// TODO: To capture flow from a partial definition of an object (i.e., a field write) to the object
// we add dataflow through partial chi operands, but only if the chi node is not the chi node for all
// aliased memory.
- iTo.getAnOperand().(ChiPartialOperand).getDef() = iFrom and not iFrom.isResultConflated()
+ iTo.getAnOperand().(ChiPartialOperand).getDef() = iFrom and not iTo.isResultConflated()
or
iTo.getAnOperand().(ChiTotalOperand).getDef() = iFrom
or
From d4338473b05a09dbaefc2324cd03228dc2e61056 Mon Sep 17 00:00:00 2001
From: Jonas Jensen
Date: Mon, 6 Apr 2020 09:01:47 +0200
Subject: [PATCH 0066/1298] C++: Enforce unique enclosing callable
Every data-flow node should have a unique enclosing function (_callable_
in the terminology of the data-flow library), but this was not evident
for the optimizer, and it led to a bad join order in `pathStep`. This
commit fixes the join order for C++ AST data flow. All other copies of
data flow seem to be fine.
These are the tuple counts for OpenJDK before this commit:
(231s) Tuple counts for DataFlowImplLocal::pathStep#fffff#cur_delta:
5882 ~0% {6} r1 = SCAN DataFlowImplLocal::PathNodeMid#class#ffffff#prev_delta AS I OUTPUT I.<2>, I.<0>, I.<1>, I.<3>, I.<4>, I.<5>
1063406780 ~0% {7} r2 = JOIN r1 WITH DataFlowImplCommon::CallContext::relevantFor_dispred#ff AS R ON FIRST 1 OUTPUT r1.<2>, R.<1>, r1.<1>, r1.<0>, r1.<3>, r1.<4>, r1.<5>
5882 ~1% {6} r3 = JOIN r2 WITH DataFlowUtil::Node::getFunction_dispred#ff AS R ON FIRST 2 OUTPUT r2.<0>, r2.<6>, r2.<2>, r2.<3>, r2.<4>, r2.<5>
105 ~0% {5} r4 = JOIN r3 WITH project#DataFlowImplLocal::LocalFlowBigStep::localFlowBigStep#ffffff_021#join_rhs AS R ON FIRST 2 OUTPUT r3.<2>, r3.<3>, r3.<4>, r3.<5>, R.<2>
5882 ~1% {6} r5 = JOIN r2 WITH DataFlowUtil::Node::getFunction_dispred#ff AS R ON FIRST 2 OUTPUT r2.<5>, r2.<2>, r2.<0>, r2.<3>, r2.<4>, r2.<6>
5882 ~0% {6} r6 = JOIN r5 WITH DataFlowImplLocal::TNil#ff_1#join_rhs AS R ON FIRST 1 OUTPUT r5.<2>, false, r5.<5>, r5.<1>, r5.<3>, r5.<4>
0 ~0% {5} r7 = JOIN r6 WITH DataFlowImplLocal::LocalFlowBigStep::localFlowBigStep#ffffff_02413#join_rhs AS R ON FIRST 3 OUTPUT R.<4>, r6.<3>, r6.<4>, r6.<5>, R.<3>
0 ~0% {5} r8 = JOIN r7 WITH DataFlowImplLocal::TNil#ff AS R ON FIRST 1 OUTPUT r7.<1>, r7.<2>, r7.<3>, R.<1>, r7.<4>
105 ~0% {5} r9 = r4 \/ r8
The problem is that `DataFlowUtil::Node::getFunction_dispred#ff`
(`getEnclosingCallable`) is joined too late.
After this commit, the tuple counts look like this:
(13s) Tuple counts for DataFlowImplLocal::pathStep#fffff#cur_delta:
5882 ~1% {6} r1 = SCAN DataFlowImplLocal::PathNodeMid#class#ffffff#prev_delta AS I OUTPUT I.<1>, I.<0>, I.<2>, I.<3>, I.<4>, I.<5>
5882 ~3% {7} r2 = JOIN r1 WITH DataFlowUtil::Node::getEnclosingCallable_dispred#ff AS R ON FIRST 1 OUTPUT r1.<2>, R.<1>, r1.<1>, r1.<0>, r1.<3>, r1.<4>, r1.<5>
5882 ~1% {6} r3 = JOIN r2 WITH DataFlowImplCommon::CallContext::relevantFor_dispred#ff AS R ON FIRST 2 OUTPUT r2.<3>, r2.<6>, r2.<2>, r2.<0>, r2.<4>, r2.<5>
105 ~0% {5} r4 = JOIN r3 WITH project#DataFlowImplLocal::LocalFlowBigStep::localFlowBigStep#ffffff_021#join_rhs AS R ON FIRST 2 OUTPUT r3.<2>, r3.<3>, r3.<4>, r3.<5>, R.<2>
5882 ~1% {6} r5 = JOIN r2 WITH DataFlowImplCommon::CallContext::relevantFor_dispred#ff AS R ON FIRST 2 OUTPUT r2.<5>, r2.<2>, r2.<3>, r2.<0>, r2.<4>, r2.<6>
5882 ~0% {6} r6 = JOIN r5 WITH DataFlowImplLocal::TNil#ff_1#join_rhs AS R ON FIRST 1 OUTPUT r5.<2>, false, r5.<5>, r5.<1>, r5.<3>, r5.<4>
0 ~0% {5} r7 = JOIN r6 WITH DataFlowImplLocal::LocalFlowBigStep::localFlowBigStep#ffffff_02413#join_rhs AS R ON FIRST 3 OUTPUT R.<4>, r6.<3>, r6.<4>, r6.<5>, R.<3>
0 ~0% {5} r8 = JOIN r7 WITH DataFlowImplLocal::TNil#ff AS R ON FIRST 1 OUTPUT r7.<1>, r7.<2>, r7.<3>, R.<1>, r7.<4>
105 ~0% {5} r9 = r4 \/ r8
There is a slight slowdown coming from the introduction of a new
predicate `DataFlowImplLocal::pathStep#fffff#join_rhs`, which is used
only in the standard order:
(12s) Tuple counts for DataFlowImplLocal::pathStep#fffff#join_rhs:
282057 ~0% {2} r1 = SCAN DataFlowImplCommon::CallContext::relevantFor_dispred#ff AS I OUTPUT I.<1>, I.<0>
9159890 ~1% {2} r2 = JOIN r1 WITH DataFlowUtil::Node::getEnclosingCallable_dispred#ff_10#join_rhs AS R ON FIRST 1 OUTPUT R.<1>, r1.<1>
return r2
The evaluation of `unique` is cheap but not free:
DataFlowUtil::Node::getEnclosingCallable_dispred#ff .............. 3.9s
DataFlowUtil::Node::getEnclosingCallable_dispred#ff_10#join_rhs .. 3.5s
The first of these two predicates evaluates `unique`, and the second
simply reorders columns. They take about the same time, which suggests
that `unique` is about as fast as it can be, given the number of tuples
it needs to push around. Note that the column reordering predicate is
only needed because of the standard order.
---
cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll
index 700087871cc..b577a3b168f 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll
@@ -43,7 +43,7 @@ class Node extends TNode {
/**
* INTERNAL: Do not use. Alternative name for `getFunction`.
*/
- Function getEnclosingCallable() { result = this.getFunction() }
+ final Function getEnclosingCallable() { result = unique( | | this.getFunction()) }
/** Gets the type of this node. */
Type getType() { none() } // overridden in subclasses
From bf7614a4c97b8df9f3b1a3f21f958c9f96b0ada8 Mon Sep 17 00:00:00 2001
From: Jonas Jensen
Date: Mon, 6 Apr 2020 14:08:19 +0200
Subject: [PATCH 0067/1298] C++: Move Expr location workaround to Expr.qll
This workaround from `DataFlowUtil.qll` should be useful for any query
that selects an `Expr`. In particular, it's useful for IR data flow.
This commit does not include test changes.
---
.../cpp/dataflow/internal/DataFlowUtil.qll | 23 +---------------
cpp/ql/src/semmle/code/cpp/exprs/Expr.qll | 27 ++++++++++++++++++-
2 files changed, 27 insertions(+), 23 deletions(-)
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll
index 700087871cc..8a1c7c584d2 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll
@@ -114,33 +114,12 @@ class ExprNode extends Node, TExprNode {
override string toString() { result = expr.toString() }
- override Location getLocation() {
- result = getExprLocationOverride(expr)
- or
- not exists(getExprLocationOverride(expr)) and
- result = expr.getLocation()
- }
+ override Location getLocation() { result = expr.getLocation() }
/** Gets the expression corresponding to this node. */
Expr getExpr() { result = expr }
}
-/**
- * Gets a location for `e` that's more accurate than `e.getLocation()`, if any.
- */
-private Location getExprLocationOverride(Expr e) {
- // Base case: the parent has a better location than `e`.
- e.getLocation() instanceof UnknownExprLocation and
- result = e.getParent().getLocation() and
- not result instanceof UnknownLocation
- or
- // Recursive case: the parent has a location override that's better than what
- // `e` has.
- e.getLocation() instanceof UnknownExprLocation and
- result = getExprLocationOverride(e.getParent()) and
- not result instanceof UnknownLocation
-}
-
abstract class ParameterNode extends Node, TNode {
/**
* Holds if this node is the parameter of `c` at the specified (zero-based)
diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll b/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll
index 97371919b02..fd15a22fbd2 100644
--- a/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll
+++ b/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll
@@ -53,7 +53,32 @@ class Expr extends StmtParent, @expr {
Element getParent() { exprparents(underlyingElement(this), _, unresolveElement(result)) }
/** Gets the location of this expression. */
- override Location getLocation() { exprs(underlyingElement(this), _, result) }
+ override Location getLocation() {
+ result = this.getExprLocationOverride()
+ or
+ not exists(this.getExprLocationOverride()) and
+ result = this.getDbLocation()
+ }
+
+ /**
+ * Gets a location for this expression that's more accurate than
+ * `getDbLocation()`, if any.
+ */
+ private Location getExprLocationOverride() {
+ // Base case: the parent has a better location than `this`.
+ this.getDbLocation() instanceof UnknownExprLocation and
+ result = this.getParent().(Expr).getDbLocation() and
+ not result instanceof UnknownLocation
+ or
+ // Recursive case: the parent has a location override that's better than
+ // what `this` has.
+ this.getDbLocation() instanceof UnknownExprLocation and
+ result = this.getParent().(Expr).getExprLocationOverride() and
+ not result instanceof UnknownLocation
+ }
+
+ /** Gets the location of this expressions, raw from the database. */
+ private Location getDbLocation() { exprs(underlyingElement(this), _, result) }
/** Holds if this is an auxiliary expression generated by the compiler. */
predicate isCompilerGenerated() {
From c5775418505de4e94753b63196106541f1ef49f0 Mon Sep 17 00:00:00 2001
From: Mathias Vorreiter Pedersen
Date: Mon, 6 Apr 2020 15:50:08 +0200
Subject: [PATCH 0068/1298] C++: Fix reverse read dataflow consistency failure
and accept tests
---
.../ir/dataflow/internal/DataFlowPrivate.qll | 6 ++---
.../cpp/ir/dataflow/internal/DataFlowUtil.qll | 22 +++++++++++++++++++
.../dataflow-ir-consistency.expected | 3 +++
.../dataflow-tests/test_diff.expected | 8 ++++---
.../dataflow/dataflow-tests/test_ir.expected | 8 +++----
.../dataflow/fields/ir-flow.expected | 21 ++++++++++++++++++
.../dataflow/taint-tests/test_diff.expected | 16 +++++---------
.../dataflow/taint-tests/test_ir.expected | 16 ++++----------
8 files changed, 68 insertions(+), 32 deletions(-)
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
index 5d99866e7ea..ddacf2dcb30 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
@@ -148,10 +148,10 @@ predicate storeStep(Node node1, Content f, PostUpdateNode node2) {
*/
predicate readStep(Node node1, Content f, Node node2) {
exists(FieldAddressInstruction fa, LoadInstruction load |
- fa.getField() = f.(FieldContent).getField() and
- node1.asInstruction() = load and
load.getSourceAddress() = fa and
- node2.asInstruction().getAnOperand().getAnyDef() = load
+ node1.asInstruction() = load.getSourceValueOperand().getAnyDef() and
+ fa.getField() = f.(FieldContent).getField() and
+ load = node2.asInstruction()
)
}
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
index 49ff9a85ad5..88d221879fd 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
@@ -257,9 +257,29 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
)
}
+ // There might be multiple `ChiInstructions` that has a particular instruction as
+ // the total operand - so this definition give consistency errors in
+ // DataFlowImplConsistency::Consistency. However, it's not clear what (if any) implications
+ // this consistency failure has.
override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() }
}
+private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNode {
+ override StoreInstruction instr;
+ FieldAddressInstruction field;
+
+ ExplicitSingleFieldStoreQualifierNode() {
+ field = instr.getDestinationAddress() and
+ not exists(ChiInstruction chi | chi.getPartial() = instr)
+ }
+
+ // Since there is no Chi instruction with a total operand for us to use we let the pre update node
+ // be the address of the object containing the field.
+ // Note that, unlike in the case where a struct has multiple fields (and thus has a `Chi`
+ // instruction), the pre update node will be an instruction with a register result.
+ override Node getPreUpdateNode() { result.asInstruction() = field.getObjectAddress() }
+}
+
/**
* A node that represents the value of a variable after a function call that
* may have changed the variable because it's passed by reference.
@@ -281,6 +301,8 @@ class DefinitionByReferenceNode extends PartialDefinitionNode {
call = write.getPrimaryInstruction()
}
+ // See the comment on ExplicitFieldStoreQualifierNode::getPreUpdateNode for comments on why
+ // this causes failures in DataFlowImplConsistency::Consistency.
override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() }
/** Gets the argument corresponding to this node. */
diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected
index 7abb7b4f4ae..99bf7799ff2 100644
--- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected
+++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected
@@ -30,6 +30,9 @@ localCallNodes
postIsNotPre
postHasUniquePre
uniquePostUpdate
+| ref.cpp:83:5:83:17 | Chi | Node has multiple PostUpdateNodes. |
+| ref.cpp:100:34:100:36 | InitializeIndirection | Node has multiple PostUpdateNodes. |
+| ref.cpp:109:5:109:22 | Chi | Node has multiple PostUpdateNodes. |
postIsInSameCallable
reverseRead
storeIsPostUpdate
diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected
index 8dae5a8dad8..11c5acc30fc 100644
--- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected
+++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected
@@ -2,6 +2,7 @@
| BarrierGuard.cpp:60:11:60:16 | BarrierGuard.cpp:62:14:62:14 | AST only |
| clang.cpp:12:9:12:20 | clang.cpp:22:8:22:20 | AST only |
| clang.cpp:28:27:28:32 | clang.cpp:30:27:30:34 | AST only |
+| clang.cpp:28:27:28:32 | clang.cpp:31:27:31:28 | IR only |
| clang.cpp:39:42:39:47 | clang.cpp:41:18:41:19 | IR only |
| dispatch.cpp:16:37:16:42 | dispatch.cpp:32:16:32:24 | IR only |
| dispatch.cpp:16:37:16:42 | dispatch.cpp:40:15:40:23 | IR only |
@@ -31,6 +32,10 @@
| ref.cpp:53:17:53:18 | ref.cpp:62:10:62:11 | AST only |
| ref.cpp:53:21:53:22 | ref.cpp:65:10:65:11 | AST only |
| ref.cpp:55:23:55:28 | ref.cpp:56:10:56:11 | AST only |
+| ref.cpp:94:15:94:20 | ref.cpp:129:13:129:15 | AST only |
+| ref.cpp:109:15:109:20 | ref.cpp:132:13:132:15 | AST only |
+| ref.cpp:122:23:122:28 | ref.cpp:123:13:123:15 | AST only |
+| ref.cpp:125:19:125:24 | ref.cpp:126:13:126:15 | AST only |
| test.cpp:75:7:75:8 | test.cpp:76:8:76:9 | AST only |
| test.cpp:83:7:83:8 | test.cpp:84:8:84:18 | AST only |
| test.cpp:83:7:83:8 | test.cpp:86:8:86:9 | AST only |
@@ -41,9 +46,6 @@
| test.cpp:359:13:359:18 | test.cpp:365:10:365:14 | AST only |
| test.cpp:373:13:373:18 | test.cpp:369:10:369:14 | AST only |
| test.cpp:373:13:373:18 | test.cpp:375:10:375:14 | AST only |
-| test.cpp:382:48:382:54 | test.cpp:385:8:385:10 | AST only |
-| test.cpp:388:53:388:59 | test.cpp:392:8:392:10 | AST only |
-| test.cpp:388:53:388:59 | test.cpp:394:10:394:12 | AST only |
| test.cpp:399:7:399:9 | test.cpp:401:8:401:10 | AST only |
| test.cpp:405:7:405:9 | test.cpp:408:8:408:10 | AST only |
| test.cpp:416:7:416:11 | test.cpp:418:8:418:12 | AST only |
diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected
index 202d9827323..f4e072d1905 100644
--- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected
+++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected
@@ -12,6 +12,7 @@
| clang.cpp:18:8:18:19 | (const int *)... | clang.cpp:12:9:12:20 | sourceArray1 |
| clang.cpp:18:8:18:19 | sourceArray1 | clang.cpp:12:9:12:20 | sourceArray1 |
| clang.cpp:29:27:29:28 | m1 | clang.cpp:28:27:28:32 | call to source |
+| clang.cpp:31:27:31:28 | m2 | clang.cpp:28:27:28:32 | call to source |
| clang.cpp:37:10:37:11 | m2 | clang.cpp:34:32:34:37 | call to source |
| clang.cpp:41:18:41:19 | m2 | clang.cpp:39:42:39:47 | call to source |
| clang.cpp:45:17:45:18 | m2 | clang.cpp:43:35:43:40 | call to source |
@@ -39,10 +40,6 @@
| globals.cpp:12:10:12:24 | flowTestGlobal1 | globals.cpp:13:23:13:28 | call to source |
| globals.cpp:19:10:19:24 | flowTestGlobal2 | globals.cpp:23:23:23:28 | call to source |
| lambdas.cpp:35:8:35:8 | a | lambdas.cpp:8:10:8:15 | call to source |
-| ref.cpp:123:13:123:15 | val | ref.cpp:122:23:122:28 | call to source |
-| ref.cpp:126:13:126:15 | val | ref.cpp:125:19:125:24 | call to source |
-| ref.cpp:129:13:129:15 | val | ref.cpp:94:15:94:20 | call to source |
-| ref.cpp:132:13:132:15 | val | ref.cpp:109:15:109:20 | call to source |
| test.cpp:7:8:7:9 | t1 | test.cpp:6:12:6:17 | call to source |
| test.cpp:9:8:9:9 | t1 | test.cpp:6:12:6:17 | call to source |
| test.cpp:10:8:10:9 | t2 | test.cpp:6:12:6:17 | call to source |
@@ -65,6 +62,9 @@
| test.cpp:266:12:266:12 | x | test.cpp:265:22:265:27 | call to source |
| test.cpp:289:14:289:14 | x | test.cpp:305:17:305:22 | call to source |
| test.cpp:318:7:318:7 | x | test.cpp:314:4:314:9 | call to source |
+| test.cpp:385:8:385:10 | tmp | test.cpp:382:48:382:54 | source1 |
+| test.cpp:392:8:392:10 | tmp | test.cpp:388:53:388:59 | source1 |
+| test.cpp:394:10:394:12 | tmp | test.cpp:388:53:388:59 | source1 |
| test.cpp:450:9:450:22 | (statement expression) | test.cpp:449:26:449:32 | source1 |
| test.cpp:461:8:461:12 | local | test.cpp:449:26:449:32 | source1 |
| true_upon_entry.cpp:13:8:13:8 | x | true_upon_entry.cpp:9:11:9:16 | call to source |
diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
index 2503be80b00..ad56e8af8a7 100644
--- a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
+++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
@@ -1,24 +1,45 @@
edges
+| aliasing.cpp:37:3:37:24 | Store : void | aliasing.cpp:38:11:38:12 | m1 |
+| aliasing.cpp:37:13:37:22 | call to user_input : void | aliasing.cpp:37:3:37:24 | Store : void |
| aliasing.cpp:37:13:37:22 | call to user_input : void | aliasing.cpp:38:11:38:12 | m1 |
+| aliasing.cpp:42:3:42:22 | Store : void | aliasing.cpp:43:13:43:14 | m1 |
+| aliasing.cpp:42:11:42:20 | call to user_input : void | aliasing.cpp:42:3:42:22 | Store : void |
| aliasing.cpp:42:11:42:20 | call to user_input : void | aliasing.cpp:43:13:43:14 | m1 |
+| aliasing.cpp:79:3:79:22 | Store : void | aliasing.cpp:80:12:80:13 | m1 |
+| aliasing.cpp:79:11:79:20 | call to user_input : void | aliasing.cpp:79:3:79:22 | Store : void |
| aliasing.cpp:79:11:79:20 | call to user_input : void | aliasing.cpp:80:12:80:13 | m1 |
+| aliasing.cpp:86:3:86:21 | Store : void | aliasing.cpp:87:12:87:13 | m1 |
+| aliasing.cpp:86:10:86:19 | call to user_input : void | aliasing.cpp:86:3:86:21 | Store : void |
| aliasing.cpp:86:10:86:19 | call to user_input : void | aliasing.cpp:87:12:87:13 | m1 |
+| aliasing.cpp:92:3:92:23 | Store : void | aliasing.cpp:93:12:93:13 | m1 |
+| aliasing.cpp:92:12:92:21 | call to user_input : void | aliasing.cpp:92:3:92:23 | Store : void |
| aliasing.cpp:92:12:92:21 | call to user_input : void | aliasing.cpp:93:12:93:13 | m1 |
+| struct_init.c:20:20:20:29 | Store : void | struct_init.c:22:11:22:11 | a |
+| struct_init.c:20:20:20:29 | call to user_input : void | struct_init.c:20:20:20:29 | Store : void |
| struct_init.c:20:20:20:29 | call to user_input : void | struct_init.c:22:11:22:11 | a |
+| struct_init.c:27:7:27:16 | Store : void | struct_init.c:31:23:31:23 | a |
+| struct_init.c:27:7:27:16 | call to user_input : void | struct_init.c:27:7:27:16 | Store : void |
| struct_init.c:27:7:27:16 | call to user_input : void | struct_init.c:31:23:31:23 | a |
nodes
+| aliasing.cpp:37:3:37:24 | Store : void | semmle.label | Store : void |
| aliasing.cpp:37:13:37:22 | call to user_input : void | semmle.label | call to user_input : void |
| aliasing.cpp:38:11:38:12 | m1 | semmle.label | m1 |
+| aliasing.cpp:42:3:42:22 | Store : void | semmle.label | Store : void |
| aliasing.cpp:42:11:42:20 | call to user_input : void | semmle.label | call to user_input : void |
| aliasing.cpp:43:13:43:14 | m1 | semmle.label | m1 |
+| aliasing.cpp:79:3:79:22 | Store : void | semmle.label | Store : void |
| aliasing.cpp:79:11:79:20 | call to user_input : void | semmle.label | call to user_input : void |
| aliasing.cpp:80:12:80:13 | m1 | semmle.label | m1 |
+| aliasing.cpp:86:3:86:21 | Store : void | semmle.label | Store : void |
| aliasing.cpp:86:10:86:19 | call to user_input : void | semmle.label | call to user_input : void |
| aliasing.cpp:87:12:87:13 | m1 | semmle.label | m1 |
+| aliasing.cpp:92:3:92:23 | Store : void | semmle.label | Store : void |
| aliasing.cpp:92:12:92:21 | call to user_input : void | semmle.label | call to user_input : void |
| aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 |
+| struct_init.c:20:20:20:29 | Store : void | semmle.label | Store : void |
| struct_init.c:20:20:20:29 | call to user_input : void | semmle.label | call to user_input : void |
| struct_init.c:22:11:22:11 | a | semmle.label | a |
+| struct_init.c:27:7:27:16 | Store : void | semmle.label | Store : void |
| struct_init.c:27:7:27:16 | call to user_input : void | semmle.label | call to user_input : void |
| struct_init.c:31:23:31:23 | a | semmle.label | a |
#select
diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected
index 9789a2bda21..ffe098d6063 100644
--- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected
+++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected
@@ -11,25 +11,21 @@
| taint.cpp:41:7:41:13 | taint.cpp:35:12:35:17 | AST only |
| taint.cpp:42:7:42:13 | taint.cpp:35:12:35:17 | AST only |
| taint.cpp:43:7:43:13 | taint.cpp:37:22:37:27 | AST only |
-| taint.cpp:88:11:88:11 | taint.cpp:77:7:77:12 | IR only |
| taint.cpp:89:11:89:11 | taint.cpp:71:22:71:27 | AST only |
-| taint.cpp:89:11:89:11 | taint.cpp:77:7:77:12 | IR only |
| taint.cpp:90:11:90:11 | taint.cpp:72:7:72:12 | AST only |
-| taint.cpp:90:11:90:11 | taint.cpp:77:7:77:12 | IR only |
-| taint.cpp:92:11:92:11 | taint.cpp:71:22:71:27 | IR only |
-| taint.cpp:92:11:92:11 | taint.cpp:72:7:72:12 | IR only |
-| taint.cpp:93:11:93:11 | taint.cpp:72:7:72:12 | IR only |
-| taint.cpp:94:11:94:11 | taint.cpp:71:22:71:27 | IR only |
-| taint.cpp:95:11:95:11 | taint.cpp:71:22:71:27 | IR only |
-| taint.cpp:95:11:95:11 | taint.cpp:72:7:72:12 | IR only |
+| taint.cpp:91:11:91:11 | taint.cpp:77:7:77:12 | AST only |
+| taint.cpp:93:11:93:11 | taint.cpp:71:22:71:27 | AST only |
+| taint.cpp:94:11:94:11 | taint.cpp:72:7:72:12 | AST only |
| taint.cpp:109:7:109:13 | taint.cpp:105:12:105:17 | IR only |
+| taint.cpp:110:7:110:13 | taint.cpp:105:12:105:17 | IR only |
+| taint.cpp:111:7:111:13 | taint.cpp:106:12:106:17 | IR only |
+| taint.cpp:112:7:112:13 | taint.cpp:106:12:106:17 | IR only |
| taint.cpp:130:7:130:9 | taint.cpp:127:8:127:13 | IR only |
| taint.cpp:137:7:137:9 | taint.cpp:120:11:120:16 | AST only |
| taint.cpp:173:8:173:13 | taint.cpp:164:19:164:24 | AST only |
| taint.cpp:181:8:181:9 | taint.cpp:185:11:185:16 | AST only |
| taint.cpp:195:7:195:7 | taint.cpp:192:23:192:28 | AST only |
| taint.cpp:195:7:195:7 | taint.cpp:193:6:193:6 | AST only |
-| taint.cpp:216:7:216:7 | taint.cpp:207:6:207:11 | AST only |
| taint.cpp:229:3:229:6 | taint.cpp:223:10:223:15 | AST only |
| taint.cpp:233:8:233:8 | taint.cpp:223:10:223:15 | AST only |
| taint.cpp:236:3:236:6 | taint.cpp:223:10:223:15 | AST only |
diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected
index 751775e21ab..e6f138e6283 100644
--- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected
+++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected
@@ -1,19 +1,10 @@
| taint.cpp:8:8:8:13 | clean1 | taint.cpp:4:27:4:33 | source1 |
| taint.cpp:16:8:16:14 | source1 | taint.cpp:12:22:12:27 | call to source |
| taint.cpp:17:8:17:16 | ++ ... | taint.cpp:12:22:12:27 | call to source |
-| taint.cpp:88:11:88:11 | a | taint.cpp:77:7:77:12 | call to source |
-| taint.cpp:89:11:89:11 | b | taint.cpp:77:7:77:12 | call to source |
-| taint.cpp:90:11:90:11 | c | taint.cpp:77:7:77:12 | call to source |
-| taint.cpp:91:11:91:11 | d | taint.cpp:77:7:77:12 | call to source |
-| taint.cpp:92:11:92:11 | a | taint.cpp:71:22:71:27 | call to source |
-| taint.cpp:92:11:92:11 | a | taint.cpp:72:7:72:12 | call to source |
-| taint.cpp:93:11:93:11 | b | taint.cpp:71:22:71:27 | call to source |
-| taint.cpp:93:11:93:11 | b | taint.cpp:72:7:72:12 | call to source |
-| taint.cpp:94:11:94:11 | c | taint.cpp:71:22:71:27 | call to source |
-| taint.cpp:94:11:94:11 | c | taint.cpp:72:7:72:12 | call to source |
-| taint.cpp:95:11:95:11 | d | taint.cpp:71:22:71:27 | call to source |
-| taint.cpp:95:11:95:11 | d | taint.cpp:72:7:72:12 | call to source |
| taint.cpp:109:7:109:13 | access to array | taint.cpp:105:12:105:17 | call to source |
+| taint.cpp:110:7:110:13 | access to array | taint.cpp:105:12:105:17 | call to source |
+| taint.cpp:111:7:111:13 | access to array | taint.cpp:106:12:106:17 | call to source |
+| taint.cpp:112:7:112:13 | access to array | taint.cpp:106:12:106:17 | call to source |
| taint.cpp:129:7:129:9 | * ... | taint.cpp:120:11:120:16 | call to source |
| taint.cpp:130:7:130:9 | * ... | taint.cpp:127:8:127:13 | call to source |
| taint.cpp:134:7:134:9 | * ... | taint.cpp:120:11:120:16 | call to source |
@@ -22,6 +13,7 @@
| taint.cpp:168:8:168:14 | tainted | taint.cpp:164:19:164:24 | call to source |
| taint.cpp:210:7:210:7 | x | taint.cpp:207:6:207:11 | call to source |
| taint.cpp:215:7:215:7 | x | taint.cpp:207:6:207:11 | call to source |
+| taint.cpp:216:7:216:7 | y | taint.cpp:207:6:207:11 | call to source |
| taint.cpp:250:8:250:8 | a | taint.cpp:223:10:223:15 | call to source |
| taint.cpp:280:7:280:7 | t | taint.cpp:275:6:275:11 | call to source |
| taint.cpp:289:7:289:7 | t | taint.cpp:275:6:275:11 | call to source |
From 3b76509159ec9ca91d7ff26a92c25078140e52d8 Mon Sep 17 00:00:00 2001
From: Jonas Jensen
Date: Mon, 6 Apr 2020 14:48:26 +0200
Subject: [PATCH 0069/1298] C++: Test DefaultTaintTracking field conflation
---
.../defaulttainttracking.cpp | 20 ++++++++++++++++++-
.../DefaultTaintTracking/tainted.expected | 11 ++++++++++
.../DefaultTaintTracking/test_diff.expected | 9 +++++++++
3 files changed, 39 insertions(+), 1 deletion(-)
diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp
index 02ae1e07154..463b7e7c718 100644
--- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp
+++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp
@@ -86,4 +86,22 @@ namespace std {
void test_std_move() {
sink(std::move(getenv("VAR")));
-}
\ No newline at end of file
+}
+
+struct Point {
+ int x;
+ int y;
+
+ void callSink() {
+ sink(this->x); // tainted
+ sink(this->y); // not tainted [FALSE POSITIVE]
+ }
+};
+
+void test_conflated_fields() {
+ Point p;
+ p.x = getenv("VAR")[0];
+ sink(p.x); // tainted
+ sink(p.y); // not tainted
+ p.callSink();
+}
diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected
index 99e970c9b40..43048104276 100644
--- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected
+++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected
@@ -101,6 +101,17 @@
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:23 | call to getenv |
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:30 | (reference to) |
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 |
+| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:10:11:10:13 | p#0 |
+| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:96:10:96:13 | this |
+| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:96:16:96:16 | x |
+| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:97:10:97:13 | this |
+| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:97:16:97:16 | y |
+| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:103:9:103:14 | call to getenv |
+| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:103:9:103:24 | (int)... |
+| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:103:9:103:24 | access to array |
+| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:104:10:104:10 | x |
+| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:106:3:106:3 | p |
+| defaulttainttracking.cpp:103:9:103:14 | call to getenv | test_diff.cpp:2:11:2:13 | p#0 |
| globals.cpp:5:20:5:25 | call to getenv | globals.cpp:2:17:2:25 | sinkParam |
| globals.cpp:5:20:5:25 | call to getenv | globals.cpp:5:12:5:16 | local |
| globals.cpp:5:20:5:25 | call to getenv | globals.cpp:5:20:5:25 | call to getenv |
diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected
index 335cca91c33..2665aec8145 100644
--- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected
+++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected
@@ -15,6 +15,15 @@
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:32 | (reference dereference) | IR only |
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:30 | (reference to) | IR only |
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 | IR only |
+| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:10:11:10:13 | p#0 | IR only |
+| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:96:10:96:13 | this | IR only |
+| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:96:16:96:16 | x | IR only |
+| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:97:10:97:13 | this | IR only |
+| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:97:16:97:16 | y | IR only |
+| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:103:5:103:5 | x | AST only |
+| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:104:10:104:10 | x | IR only |
+| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:106:3:106:3 | p | IR only |
+| defaulttainttracking.cpp:103:9:103:14 | call to getenv | test_diff.cpp:2:11:2:13 | p#0 | IR only |
| globals.cpp:13:15:13:20 | call to getenv | globals.cpp:13:5:13:11 | global1 | AST only |
| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:23:5:23:11 | global2 | AST only |
| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) | IR only |
From e37aab5002a4f887959fa90677848ecf56af57b4 Mon Sep 17 00:00:00 2001
From: Jonas Jensen
Date: Mon, 6 Apr 2020 15:10:47 +0200
Subject: [PATCH 0070/1298] C++: Suppress FieldAddressInstruction taint
See code comment. This fixes false positives on openjdk/jdk.
---
.../code/cpp/ir/dataflow/DefaultTaintTracking.qll | 10 +++++++++-
.../DefaultTaintTracking/defaulttainttracking.cpp | 4 ++--
.../dataflow/DefaultTaintTracking/tainted.expected | 2 --
.../dataflow/DefaultTaintTracking/test_diff.expected | 2 --
4 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll
index d932ad30b87..10aa162e3e0 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll
@@ -187,7 +187,15 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) {
// Flow through pointer dereference
i2.(LoadInstruction).getSourceAddress() = i1
or
- i2.(UnaryInstruction).getUnary() = i1
+ // Unary instructions tend to preserve enough information in practice that we
+ // want taint to flow through.
+ // The exception is `FieldAddressInstruction`. Together with the rule for
+ // `LoadInstruction` above and for `ChiInstruction` below, flow through
+ // `FieldAddressInstruction` could cause flow into one field to come out an
+ // unrelated field. This would happen across function boundaries, where the IR
+ // would not be able to match loads to stores.
+ i2.(UnaryInstruction).getUnary() = i1 and
+ not i2 instanceof FieldAddressInstruction
or
i2.(ChiInstruction).getPartial() = i1 and
not i2.isResultConflated()
diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp
index 463b7e7c718..19496381fba 100644
--- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp
+++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp
@@ -93,8 +93,8 @@ struct Point {
int y;
void callSink() {
- sink(this->x); // tainted
- sink(this->y); // not tainted [FALSE POSITIVE]
+ sink(this->x); // tainted [NOT DETECTED]
+ sink(this->y); // not tainted
}
};
diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected
index 43048104276..2b8cd83e6fe 100644
--- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected
+++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected
@@ -103,9 +103,7 @@
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 |
| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:10:11:10:13 | p#0 |
| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:96:10:96:13 | this |
-| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:96:16:96:16 | x |
| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:97:10:97:13 | this |
-| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:97:16:97:16 | y |
| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:103:9:103:14 | call to getenv |
| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:103:9:103:24 | (int)... |
| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:103:9:103:24 | access to array |
diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected
index 2665aec8145..3e152a00a14 100644
--- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected
+++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected
@@ -17,9 +17,7 @@
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 | IR only |
| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:10:11:10:13 | p#0 | IR only |
| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:96:10:96:13 | this | IR only |
-| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:96:16:96:16 | x | IR only |
| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:97:10:97:13 | this | IR only |
-| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:97:16:97:16 | y | IR only |
| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:103:5:103:5 | x | AST only |
| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:104:10:104:10 | x | IR only |
| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:106:3:106:3 | p | IR only |
From c1ba1345df23925e1d88d07ff789d0fd1f75f0f1 Mon Sep 17 00:00:00 2001
From: Rebecca Valentine
Date: Mon, 6 Apr 2020 11:03:42 -0700
Subject: [PATCH 0071/1298] Python: ObjAPI to ValAPI: WrongNumArgsInCall:
ObjectAPI.qll: Adds doc for getAnInferredType
---
python/ql/src/semmle/python/objects/ObjectAPI.qll | 2 ++
1 file changed, 2 insertions(+)
diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll
index 5a09f0c8893..d870e19e9c6 100644
--- a/python/ql/src/semmle/python/objects/ObjectAPI.qll
+++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll
@@ -621,6 +621,8 @@ abstract class FunctionValue extends CallableValue {
bm.getFunction() = this
)
}
+
+ /** Gets a class that this function may return */
abstract ClassValue getAnInferredReturnType();
}
From 1077ce3a35086a3b1463505691edfebf26c2b584 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Tue, 7 Apr 2020 09:26:14 +0200
Subject: [PATCH 0072/1298] Python: Add FN for py/unused-import
---
.../test/query-tests/Imports/unused/UnusedImport.expected | 1 +
.../test/query-tests/Imports/unused/import_structure_1.py | 8 ++++++++
.../test/query-tests/Imports/unused/import_structure_2.py | 8 ++++++++
3 files changed, 17 insertions(+)
create mode 100644 python/ql/test/query-tests/Imports/unused/import_structure_1.py
create mode 100644 python/ql/test/query-tests/Imports/unused/import_structure_2.py
diff --git a/python/ql/test/query-tests/Imports/unused/UnusedImport.expected b/python/ql/test/query-tests/Imports/unused/UnusedImport.expected
index 163bcab7b3d..95e91ded7ad 100644
--- a/python/ql/test/query-tests/Imports/unused/UnusedImport.expected
+++ b/python/ql/test/query-tests/Imports/unused/UnusedImport.expected
@@ -1,3 +1,4 @@
+| import_structure_2.py:6:1:6:23 | Import | Import of 'bar' is not used. |
| imports_test.py:2:1:2:23 | Import | Import of 'module2' is not used. |
| imports_test.py:6:1:6:12 | Import | Import of 'cycle' is not used. |
| imports_test.py:10:1:10:22 | Import | Import of 'top_level_cycle' is not used. |
diff --git a/python/ql/test/query-tests/Imports/unused/import_structure_1.py b/python/ql/test/query-tests/Imports/unused/import_structure_1.py
new file mode 100644
index 00000000000..a76fe99f12c
--- /dev/null
+++ b/python/ql/test/query-tests/Imports/unused/import_structure_1.py
@@ -0,0 +1,8 @@
+# there should be no difference whether you import 2 things on 1 line, or use 2
+# lines
+from typing import Optional
+
+from unknown import foo, bar
+
+
+var: Optional['foo'] = None
diff --git a/python/ql/test/query-tests/Imports/unused/import_structure_2.py b/python/ql/test/query-tests/Imports/unused/import_structure_2.py
new file mode 100644
index 00000000000..90d4255ba39
--- /dev/null
+++ b/python/ql/test/query-tests/Imports/unused/import_structure_2.py
@@ -0,0 +1,8 @@
+# there should be no difference whether you import 2 things on 1 line, or use 2
+# lines
+from typing import Optional
+
+from unknown import foo
+from unknown import bar
+
+var: Optional['foo'] = None
From 75e6470009f21ed7f4b92323204dd42d001ea89c Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Tue, 7 Apr 2020 09:41:42 +0200
Subject: [PATCH 0073/1298] Python: Fix FN in py/unused-import
---
python/ql/src/Imports/UnusedImport.ql | 20 ++++++++++---------
.../Imports/unused/UnusedImport.expected | 1 +
2 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/python/ql/src/Imports/UnusedImport.ql b/python/ql/src/Imports/UnusedImport.ql
index ac93d9886f1..b8e4903b743 100644
--- a/python/ql/src/Imports/UnusedImport.ql
+++ b/python/ql/src/Imports/UnusedImport.ql
@@ -62,7 +62,7 @@ private string doctest_in_scope(Scope scope) {
}
pragma[noinline]
-private string typehint_annotation_in_file(File file) {
+private string typehint_annotation_in_module(Module module_scope) {
exists(StrConst annotation |
annotation = any(Arguments a).getAnAnnotation().getASubExpression*()
or
@@ -71,7 +71,7 @@ private string typehint_annotation_in_file(File file) {
annotation = any(FunctionExpr f).getReturns().getASubExpression*()
|
annotation.pointsTo(Value::forString(result)) and
- file = annotation.getLocation().getFile()
+ annotation.getEnclosingModule() = module_scope
)
}
@@ -84,17 +84,19 @@ private string typehint_comment_in_file(File file) {
)
}
-predicate imported_module_used_in_typehint(Import imp) {
- exists(string modname, File file |
- imp.getAName().getAsname().(Name).getId() = modname and
- file = imp.getScope().(Module).getFile()
+/** Holds if the imported alias `name` from `imp` is used in a typehint (in the same file as `imp`) */
+predicate imported_alias_used_in_typehint(Import imp, Variable name) {
+ imp.getAName().getAsname().(Name).getVariable() = name and
+ exists(File file, Module module_scope |
+ module_scope = imp.getEnclosingModule() and
+ file = module_scope.getFile()
|
// Look for type hints containing the patterns:
// # type: …name…
- typehint_comment_in_file(file).regexpMatch("# type:.*" + modname + ".*")
+ typehint_comment_in_file(file).regexpMatch("# type:.*" + name.getId() + ".*")
or
// Type hint is inside a string annotation, as needed for forward references
- typehint_annotation_in_file(file).regexpMatch(".*\\b" + modname + "\\b.*")
+ typehint_annotation_in_module(module_scope).regexpMatch(".*\\b" + name.getId() + "\\b.*")
)
}
@@ -114,7 +116,7 @@ predicate unused_import(Import imp, Variable name) {
// Assume that opaque `__all__` includes imported module
not all_not_understood(imp.getEnclosingModule()) and
not imported_module_used_in_doctest(imp) and
- not imported_module_used_in_typehint(imp) and
+ not imported_alias_used_in_typehint(imp, name) and
// Only consider import statements that actually point-to something (possibly an unknown module).
// If this is not the case, it's likely that the import statement never gets executed.
imp.getAName().getValue().pointsTo(_)
diff --git a/python/ql/test/query-tests/Imports/unused/UnusedImport.expected b/python/ql/test/query-tests/Imports/unused/UnusedImport.expected
index 95e91ded7ad..47bedf61d7c 100644
--- a/python/ql/test/query-tests/Imports/unused/UnusedImport.expected
+++ b/python/ql/test/query-tests/Imports/unused/UnusedImport.expected
@@ -1,3 +1,4 @@
+| import_structure_1.py:5:1:5:28 | Import | Import of 'bar' is not used. |
| import_structure_2.py:6:1:6:23 | Import | Import of 'bar' is not used. |
| imports_test.py:2:1:2:23 | Import | Import of 'module2' is not used. |
| imports_test.py:6:1:6:12 | Import | Import of 'cycle' is not used. |
From 6ed7b3dd927c72f0d42bf3396311d3192884c1a7 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Tue, 7 Apr 2020 11:22:16 +0200
Subject: [PATCH 0074/1298] Python: Add tests to illustrate shortcomings of
current tests filter
---
python/ql/test/library-tests/filters/tests/Filter.expected | 6 +++---
python/ql/test/library-tests/filters/tests/Filter.ql | 2 +-
python/ql/test/library-tests/filters/tests/test.py | 2 --
python/ql/test/library-tests/filters/tests/test_foo.py | 4 ++++
python/ql/test/library-tests/filters/tests/unittest_test.py | 5 +++++
5 files changed, 13 insertions(+), 6 deletions(-)
create mode 100644 python/ql/test/library-tests/filters/tests/test_foo.py
create mode 100644 python/ql/test/library-tests/filters/tests/unittest_test.py
diff --git a/python/ql/test/library-tests/filters/tests/Filter.expected b/python/ql/test/library-tests/filters/tests/Filter.expected
index 7e2143c9ac4..98932d46e51 100644
--- a/python/ql/test/library-tests/filters/tests/Filter.expected
+++ b/python/ql/test/library-tests/filters/tests/Filter.expected
@@ -1,3 +1,3 @@
-| Class MyTest |
-| Function test_1 |
-| Function test_2 |
+| test.py:4:1:4:23 | Class MyTest |
+| test.py:6:5:6:21 | Function test_1 |
+| test.py:9:5:9:21 | Function test_2 |
diff --git a/python/ql/test/library-tests/filters/tests/Filter.ql b/python/ql/test/library-tests/filters/tests/Filter.ql
index 71d6d2c668d..0528a318f77 100644
--- a/python/ql/test/library-tests/filters/tests/Filter.ql
+++ b/python/ql/test/library-tests/filters/tests/Filter.ql
@@ -2,4 +2,4 @@ import python
import semmle.python.filters.Tests
from TestScope t
-select t.toString()
+select t
diff --git a/python/ql/test/library-tests/filters/tests/test.py b/python/ql/test/library-tests/filters/tests/test.py
index cfcdc56ba64..261d2fc9f36 100644
--- a/python/ql/test/library-tests/filters/tests/test.py
+++ b/python/ql/test/library-tests/filters/tests/test.py
@@ -1,5 +1,3 @@
-
-
class TestCase:
pass
diff --git a/python/ql/test/library-tests/filters/tests/test_foo.py b/python/ql/test/library-tests/filters/tests/test_foo.py
new file mode 100644
index 00000000000..d46d7b6948c
--- /dev/null
+++ b/python/ql/test/library-tests/filters/tests/test_foo.py
@@ -0,0 +1,4 @@
+# This is running under some unknown framework, but is clearly a test!
+
+def test_foo():
+ assert True
diff --git a/python/ql/test/library-tests/filters/tests/unittest_test.py b/python/ql/test/library-tests/filters/tests/unittest_test.py
new file mode 100644
index 00000000000..6d28a61438a
--- /dev/null
+++ b/python/ql/test/library-tests/filters/tests/unittest_test.py
@@ -0,0 +1,5 @@
+import unittest
+
+class FooTest(unittest.TestCase):
+ def test_valid(self):
+ pass
From 2871eb307a35e2e7856212208cada23f1f226437 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Tue, 7 Apr 2020 11:24:06 +0200
Subject: [PATCH 0075/1298] Python: Fix (some) shortcomings of tests filter
---
python/ql/src/semmle/python/filters/Tests.qll | 17 ++++++++++++-----
.../library-tests/filters/tests/Filter.expected | 3 +++
2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/python/ql/src/semmle/python/filters/Tests.qll b/python/ql/src/semmle/python/filters/Tests.qll
index 7b9c2fa38cd..b4fb59fda07 100644
--- a/python/ql/src/semmle/python/filters/Tests.qll
+++ b/python/ql/src/semmle/python/filters/Tests.qll
@@ -5,18 +5,17 @@ abstract class TestScope extends Scope { }
// don't extend Class directly to avoid ambiguous method warnings
class UnitTestClass extends TestScope {
UnitTestClass() {
- exists(ClassObject c | this = c.getPyClass() |
- c.getASuperType() = theUnitTestPackage().attr(_)
+ exists(ClassValue cls | this = cls.getScope() |
+ cls.getABaseType+() = Module::named("unittest").attr(_)
or
- c.getASuperType().getName().toLowerCase() = "testcase"
+ cls.getABaseType+().getName().toLowerCase() = "testcase"
)
}
}
-PackageObject theUnitTestPackage() { result.getName() = "unittest" }
-
abstract class Test extends TestScope { }
+/** Class of test function that uses the `unittest` framework */
class UnitTestFunction extends Test {
UnitTestFunction() {
this.getScope+() instanceof UnitTestClass and
@@ -37,3 +36,11 @@ class NoseTestFunction extends Test {
this.(Function).getName().matches("test%")
}
}
+
+/** Class of functions that are clearly tests, but don't belong to a specific framework */
+class UnknownTestFunction extends Test {
+ UnknownTestFunction() {
+ this.(Function).getName().matches("test%") and
+ this.getEnclosingModule().getFile().getShortName().matches("test_%.py")
+ }
+}
diff --git a/python/ql/test/library-tests/filters/tests/Filter.expected b/python/ql/test/library-tests/filters/tests/Filter.expected
index 98932d46e51..a4f643aac45 100644
--- a/python/ql/test/library-tests/filters/tests/Filter.expected
+++ b/python/ql/test/library-tests/filters/tests/Filter.expected
@@ -1,3 +1,6 @@
| test.py:4:1:4:23 | Class MyTest |
| test.py:6:5:6:21 | Function test_1 |
| test.py:9:5:9:21 | Function test_2 |
+| test_foo.py:3:1:3:15 | Function test_foo |
+| unittest_test.py:3:1:3:33 | Class FooTest |
+| unittest_test.py:4:5:4:25 | Function test_valid |
From 46ecbef8f2abb06ac407c28afe43c9db5bc29eca Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Tue, 7 Apr 2020 11:42:13 +0200
Subject: [PATCH 0076/1298] Python: Consistenly use TestScope instead of Test
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
It's not clear which one is the correct to use, but there were more uses of
TestScope than Test, so I'm assuming that is the right one ¯\_(ツ)_/¯
---
python/ql/src/Statements/AssertLiteralConstant.ql | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/python/ql/src/Statements/AssertLiteralConstant.ql b/python/ql/src/Statements/AssertLiteralConstant.ql
index cdb39ff0955..cea2d7302f2 100644
--- a/python/ql/src/Statements/AssertLiteralConstant.ql
+++ b/python/ql/src/Statements/AssertLiteralConstant.ql
@@ -17,7 +17,7 @@ import semmle.python.filters.Tests
from Assert a, string value
where
/* Exclude asserts inside test cases */
- not a.getScope() instanceof Test and
+ not a.getScope().getScope*() instanceof TestScope and
exists(Expr test | test = a.getTest() |
value = test.(IntegerLiteral).getN()
or
From 94ccc16f858ab1aa205f62ae8dc04a43a2577778 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Tue, 7 Apr 2020 11:26:56 +0200
Subject: [PATCH 0077/1298] Python: iter str/seq query gives non-useful results
with tests
---
.../iter/IterableStringOrSequence.expected | 2 ++
.../iter/supress_uses_from_tests.py | 19 +++++++++++++++++++
2 files changed, 21 insertions(+)
create mode 100644 python/ql/test/3/query-tests/Statements/iter/supress_uses_from_tests.py
diff --git a/python/ql/test/3/query-tests/Statements/iter/IterableStringOrSequence.expected b/python/ql/test/3/query-tests/Statements/iter/IterableStringOrSequence.expected
index 184dd03d9e5..6f40655b926 100644
--- a/python/ql/test/3/query-tests/Statements/iter/IterableStringOrSequence.expected
+++ b/python/ql/test/3/query-tests/Statements/iter/IterableStringOrSequence.expected
@@ -1 +1,3 @@
| statements_test.py:21:5:21:19 | For | Iteration over $@, of class list, may also iterate over $@. | statements_test.py:20:13:20:33 | ControlFlowNode for List | sequence | statements_test.py:18:13:18:26 | ControlFlowNode for Str | string |
+| supress_uses_from_tests.py:6:5:6:20 | For | Iteration over $@, of class list, may also iterate over $@. | supress_uses_from_tests.py:9:5:9:26 | ControlFlowNode for List | sequence | supress_uses_from_tests.py:19:17:19:27 | ControlFlowNode for Str | string |
+| supress_uses_from_tests.py:6:5:6:20 | For | Iteration over $@, of class list, may also iterate over $@. | supress_uses_from_tests.py:15:13:15:34 | ControlFlowNode for List | sequence | supress_uses_from_tests.py:19:17:19:27 | ControlFlowNode for Str | string |
diff --git a/python/ql/test/3/query-tests/Statements/iter/supress_uses_from_tests.py b/python/ql/test/3/query-tests/Statements/iter/supress_uses_from_tests.py
new file mode 100644
index 00000000000..0afbf50f61c
--- /dev/null
+++ b/python/ql/test/3/query-tests/Statements/iter/supress_uses_from_tests.py
@@ -0,0 +1,19 @@
+# This example illustrates that all valid results are not useful.
+# The alert in this file should be suppressed (TODO).
+# see https://github.com/Semmle/ql/issues/3207
+
+def foo(l):
+ for (k, v) in l:
+ print(k, v)
+
+foo([('a', 42), ('b', 43)])
+
+import unittest
+
+class FooTest(unittest.TestCase):
+ def test_valid(self):
+ foo([('a', 42), ('b', 43)])
+
+ def test_not_valid(self):
+ with six.assertRaises(self, ValueError):
+ foo("not valid")
From befe73df1482707edc773967002fa76e84ebea82 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Tue, 7 Apr 2020 11:27:45 +0200
Subject: [PATCH 0078/1298] Python: supress non-useful results (w/ tests) for
iter str/seq query
Fixes https://github.com/Semmle/ql/issues/3207
---
python/ql/src/Statements/IterableStringOrSequence.ql | 6 +++++-
.../Statements/iter/IterableStringOrSequence.expected | 2 --
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/python/ql/src/Statements/IterableStringOrSequence.ql b/python/ql/src/Statements/IterableStringOrSequence.ql
index 4813a3858e0..7ab43f33b76 100644
--- a/python/ql/src/Statements/IterableStringOrSequence.ql
+++ b/python/ql/src/Statements/IterableStringOrSequence.ql
@@ -12,6 +12,7 @@
*/
import python
+import semmle.python.filters.Tests
predicate has_string_type(Value v) {
v.getClass() = ClassValue::str()
@@ -28,7 +29,10 @@ where
iter.pointsTo(seq, seq_origin) and
has_string_type(str) and
seq.getClass().isIterable() and
- not has_string_type(seq)
+ not has_string_type(seq) and
+ // suppress occurrences from tests
+ not seq_origin.getScope().getScope*() instanceof TestScope and
+ not str_origin.getScope().getScope*() instanceof TestScope
select loop,
"Iteration over $@, of class " + seq.getClass().getName() + ", may also iterate over $@.",
seq_origin, "sequence", str_origin, "string"
diff --git a/python/ql/test/3/query-tests/Statements/iter/IterableStringOrSequence.expected b/python/ql/test/3/query-tests/Statements/iter/IterableStringOrSequence.expected
index 6f40655b926..184dd03d9e5 100644
--- a/python/ql/test/3/query-tests/Statements/iter/IterableStringOrSequence.expected
+++ b/python/ql/test/3/query-tests/Statements/iter/IterableStringOrSequence.expected
@@ -1,3 +1 @@
| statements_test.py:21:5:21:19 | For | Iteration over $@, of class list, may also iterate over $@. | statements_test.py:20:13:20:33 | ControlFlowNode for List | sequence | statements_test.py:18:13:18:26 | ControlFlowNode for Str | string |
-| supress_uses_from_tests.py:6:5:6:20 | For | Iteration over $@, of class list, may also iterate over $@. | supress_uses_from_tests.py:9:5:9:26 | ControlFlowNode for List | sequence | supress_uses_from_tests.py:19:17:19:27 | ControlFlowNode for Str | string |
-| supress_uses_from_tests.py:6:5:6:20 | For | Iteration over $@, of class list, may also iterate over $@. | supress_uses_from_tests.py:15:13:15:34 | ControlFlowNode for List | sequence | supress_uses_from_tests.py:19:17:19:27 | ControlFlowNode for Str | string |
From 5719967a8ed77088a94fbbec567819ba19ab348f Mon Sep 17 00:00:00 2001
From: Mathias Vorreiter Pedersen
Date: Tue, 7 Apr 2020 12:03:28 +0200
Subject: [PATCH 0079/1298] C++: Remove single-field case from PostUpdateNode
and accept tests
---
.../ir/dataflow/internal/DataFlowPrivate.qll | 10 ++--
.../cpp/ir/dataflow/internal/DataFlowUtil.qll | 52 +++++++------------
.../dataflow-ir-consistency.expected | 1 -
.../dataflow/fields/ir-flow.expected | 10 ++++
.../CWE-134/semmle/funcs/funcsLocal.expected | 1 +
5 files changed, 33 insertions(+), 41 deletions(-)
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
index ddacf2dcb30..f81be05c66b 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
@@ -131,12 +131,10 @@ private class ArrayContent extends Content, TArrayContent {
* value of `node1`.
*/
predicate storeStep(Node node1, Content f, PostUpdateNode node2) {
- exists(FieldAddressInstruction fa |
- exists(StoreInstruction store |
- node1.asInstruction() = store and
- store.getDestinationAddress() = fa
- ) and
- node2.getPreUpdateNode().asInstruction() = fa.getObjectAddress() and
+ exists(FieldAddressInstruction fa, StoreInstruction store |
+ node1.asInstruction() = store and
+ store.getDestinationAddress() = fa and
+ node2.asInstruction().(ChiInstruction).getPartial() = store and
f.(FieldContent).getField() = fa.getField()
)
}
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
index 88d221879fd..a7a5f9d6d86 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
@@ -264,22 +264,6 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() }
}
-private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNode {
- override StoreInstruction instr;
- FieldAddressInstruction field;
-
- ExplicitSingleFieldStoreQualifierNode() {
- field = instr.getDestinationAddress() and
- not exists(ChiInstruction chi | chi.getPartial() = instr)
- }
-
- // Since there is no Chi instruction with a total operand for us to use we let the pre update node
- // be the address of the object containing the field.
- // Note that, unlike in the case where a struct has multiple fields (and thus has a `Chi`
- // instruction), the pre update node will be an instruction with a register result.
- override Node getPreUpdateNode() { result.asInstruction() = field.getObjectAddress() }
-}
-
/**
* A node that represents the value of a variable after a function call that
* may have changed the variable because it's passed by reference.
@@ -290,31 +274,31 @@ private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNod
* returned. This node will have its `getArgument()` equal to `&x` and its
* `getVariableAccess()` equal to `x`.
*/
-class DefinitionByReferenceNode extends PartialDefinitionNode {
- override ChiInstruction instr;
- WriteSideEffectInstruction write;
- CallInstruction call;
-
- DefinitionByReferenceNode() {
- not instr.isResultConflated() and
- instr.getPartial() = write and
- call = write.getPrimaryInstruction()
- }
-
- // See the comment on ExplicitFieldStoreQualifierNode::getPreUpdateNode for comments on why
- // this causes failures in DataFlowImplConsistency::Consistency.
- override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() }
+class DefinitionByReferenceNode extends InstructionNode {
+ override WriteSideEffectInstruction instr;
/** Gets the argument corresponding to this node. */
Expr getArgument() {
- result = call.getPositionalArgument(write.getIndex()).getUnconvertedResultExpression()
+ result =
+ instr
+ .getPrimaryInstruction()
+ .(CallInstruction)
+ .getPositionalArgument(instr.getIndex())
+ .getUnconvertedResultExpression()
or
- result = call.getThisArgument().getUnconvertedResultExpression() and
- write.getIndex() = -1
+ result =
+ instr
+ .getPrimaryInstruction()
+ .(CallInstruction)
+ .getThisArgument()
+ .getUnconvertedResultExpression() and
+ instr.getIndex() = -1
}
/** Gets the parameter through which this value is assigned. */
- Parameter getParameter() { result = call.getStaticCallTarget().getParameter(write.getIndex()) }
+ Parameter getParameter() {
+ exists(CallInstruction ci | result = ci.getStaticCallTarget().getParameter(instr.getIndex()))
+ }
}
/**
diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected
index 99bf7799ff2..3940c1e8389 100644
--- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected
+++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected
@@ -31,7 +31,6 @@ postIsNotPre
postHasUniquePre
uniquePostUpdate
| ref.cpp:83:5:83:17 | Chi | Node has multiple PostUpdateNodes. |
-| ref.cpp:100:34:100:36 | InitializeIndirection | Node has multiple PostUpdateNodes. |
| ref.cpp:109:5:109:22 | Chi | Node has multiple PostUpdateNodes. |
postIsInSameCallable
reverseRead
diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
index ad56e8af8a7..6d34e81e849 100644
--- a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
+++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
@@ -5,6 +5,10 @@ edges
| aliasing.cpp:42:3:42:22 | Store : void | aliasing.cpp:43:13:43:14 | m1 |
| aliasing.cpp:42:11:42:20 | call to user_input : void | aliasing.cpp:42:3:42:22 | Store : void |
| aliasing.cpp:42:11:42:20 | call to user_input : void | aliasing.cpp:43:13:43:14 | m1 |
+| aliasing.cpp:60:3:60:22 | Chi [m1] : void | aliasing.cpp:61:13:61:14 | Store [m1] : void |
+| aliasing.cpp:60:3:60:22 | Store : void | aliasing.cpp:60:3:60:22 | Chi [m1] : void |
+| aliasing.cpp:60:11:60:20 | call to user_input : void | aliasing.cpp:60:3:60:22 | Store : void |
+| aliasing.cpp:61:13:61:14 | Store [m1] : void | aliasing.cpp:62:14:62:15 | m1 |
| aliasing.cpp:79:3:79:22 | Store : void | aliasing.cpp:80:12:80:13 | m1 |
| aliasing.cpp:79:11:79:20 | call to user_input : void | aliasing.cpp:79:3:79:22 | Store : void |
| aliasing.cpp:79:11:79:20 | call to user_input : void | aliasing.cpp:80:12:80:13 | m1 |
@@ -27,6 +31,11 @@ nodes
| aliasing.cpp:42:3:42:22 | Store : void | semmle.label | Store : void |
| aliasing.cpp:42:11:42:20 | call to user_input : void | semmle.label | call to user_input : void |
| aliasing.cpp:43:13:43:14 | m1 | semmle.label | m1 |
+| aliasing.cpp:60:3:60:22 | Chi [m1] : void | semmle.label | Chi [m1] : void |
+| aliasing.cpp:60:3:60:22 | Store : void | semmle.label | Store : void |
+| aliasing.cpp:60:11:60:20 | call to user_input : void | semmle.label | call to user_input : void |
+| aliasing.cpp:61:13:61:14 | Store [m1] : void | semmle.label | Store [m1] : void |
+| aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 |
| aliasing.cpp:79:3:79:22 | Store : void | semmle.label | Store : void |
| aliasing.cpp:79:11:79:20 | call to user_input : void | semmle.label | call to user_input : void |
| aliasing.cpp:80:12:80:13 | m1 | semmle.label | m1 |
@@ -45,6 +54,7 @@ nodes
#select
| aliasing.cpp:38:11:38:12 | m1 | aliasing.cpp:37:13:37:22 | call to user_input : void | aliasing.cpp:38:11:38:12 | m1 | m1 flows from $@ | aliasing.cpp:37:13:37:22 | call to user_input : void | call to user_input : void |
| aliasing.cpp:43:13:43:14 | m1 | aliasing.cpp:42:11:42:20 | call to user_input : void | aliasing.cpp:43:13:43:14 | m1 | m1 flows from $@ | aliasing.cpp:42:11:42:20 | call to user_input : void | call to user_input : void |
+| aliasing.cpp:62:14:62:15 | m1 | aliasing.cpp:60:11:60:20 | call to user_input : void | aliasing.cpp:62:14:62:15 | m1 | m1 flows from $@ | aliasing.cpp:60:11:60:20 | call to user_input : void | call to user_input : void |
| aliasing.cpp:80:12:80:13 | m1 | aliasing.cpp:79:11:79:20 | call to user_input : void | aliasing.cpp:80:12:80:13 | m1 | m1 flows from $@ | aliasing.cpp:79:11:79:20 | call to user_input : void | call to user_input : void |
| aliasing.cpp:87:12:87:13 | m1 | aliasing.cpp:86:10:86:19 | call to user_input : void | aliasing.cpp:87:12:87:13 | m1 | m1 flows from $@ | aliasing.cpp:86:10:86:19 | call to user_input : void | call to user_input : void |
| aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input : void | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input : void | call to user_input : void |
diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected
index 2417990beb2..5ae6a003bed 100644
--- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected
+++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected
@@ -5,3 +5,4 @@
| funcsLocal.c:37:9:37:10 | i5 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:36:7:36:8 | i5 | gets |
| funcsLocal.c:42:9:42:10 | i6 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:41:13:41:16 | call to gets | gets |
| funcsLocal.c:42:9:42:10 | i6 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:41:18:41:20 | i61 | gets |
+| funcsLocal.c:58:9:58:10 | e1 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:16:8:16:9 | i1 | fread |
From 39eb1a38258011fe96118b6b1ef4789e50454e00 Mon Sep 17 00:00:00 2001
From: Calum Grant
Date: Tue, 11 Feb 2020 19:34:56 +0000
Subject: [PATCH 0080/1298] C#: Remove assembly qualifier from some trap-ids.
---
.../Semmle.Extraction.CSharp/Entities/Method.cs | 5 +----
.../Semmle.Extraction.CSharp/Entities/Types/NamedType.cs | 8 ++++++--
.../Semmle.Extraction.CSharp/Entities/Types/TupleType.cs | 2 +-
.../Semmle.Extraction.CSharp/SymbolExtensions.cs | 9 ++++-----
4 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs
index 999903a1da8..21538a57741 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs
@@ -201,10 +201,7 @@ namespace Semmle.Extraction.CSharp.Entities
///
protected static void AddSignatureTypeToId(Context cx, TextWriter trapFile, IMethodSymbol method, ITypeSymbol type)
{
- if (type.ContainsTypeParameters(cx, method))
- type.BuildTypeId(cx, trapFile, (cx0, tb0, type0) => AddSignatureTypeToId(cx, tb0, method, type0));
- else
- trapFile.WriteSubId(Type.Create(cx, type));
+ type.BuildTypeId(cx, trapFile, false, (cx0, tb0, type0) => AddSignatureTypeToId(cx, tb0, method, type0));
}
protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethodSymbol method)
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs
index cecec5bc028..4e584180c7c 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs
@@ -111,7 +111,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
- symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub)));
+ symbol.BuildTypeId(Context, trapFile, true, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub)));
trapFile.Write(";type");
}
@@ -177,7 +177,11 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
- trapFile.WriteSubId(referencedType);
+ void WriteType(Context cx, TextWriter trapFile, ITypeSymbol symbol)
+ {
+ symbol.BuildTypeId(cx, trapFile, false, WriteType);
+ }
+ WriteType(Context, trapFile, referencedType.symbol);
trapFile.Write(";typeRef");
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs
index de6ea217084..e0adee16142 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs
@@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
- symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub)));
+ symbol.BuildTypeId(Context, trapFile, false, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub)));
trapFile.Write(";tuple");
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs
index 6050ad910a5..c871da6e59a 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs
@@ -131,9 +131,9 @@ namespace Semmle.Extraction.CSharp
/// The extraction context.
/// The trap builder used to store the result.
/// The action to apply to syntactic sub terms of this type.
- public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, Action subTermAction)
+ public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, bool prefix, Action subTermAction)
{
- if (type.SpecialType != SpecialType.None)
+ if (type.SpecialType != SpecialType.None && !(type is INamedTypeSymbol n && n.IsGenericType))
{
/*
* Use the keyword ("int" etc) for the built-in types.
@@ -160,7 +160,7 @@ namespace Semmle.Extraction.CSharp
case TypeKind.Delegate:
case TypeKind.Error:
var named = (INamedTypeSymbol)type;
- named.BuildNamedTypeId(cx, trapFile, subTermAction);
+ named.BuildNamedTypeId(cx, trapFile, prefix, subTermAction);
return;
case TypeKind.Pointer:
var ptr = (IPointerTypeSymbol)type;
@@ -211,9 +211,8 @@ namespace Semmle.Extraction.CSharp
trapFile.Write("::");
}
- static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, Action subTermAction)
+ static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, bool prefixAssembly, Action subTermAction)
{
- bool prefixAssembly = true;
if (named.ContainingAssembly is null) prefixAssembly = false;
if (named.IsTupleType)
From 9ec0c8f3ec1a0b5df05fdfcc54ead9876572ff88 Mon Sep 17 00:00:00 2001
From: Calum Grant
Date: Wed, 12 Feb 2020 13:52:17 +0000
Subject: [PATCH 0081/1298] C#: Qualify type parameters with the entity that
declares them
---
.../Entities/Constructor.cs | 2 +-
.../Entities/Method.cs | 14 +++----
.../Entities/Types/NamedType.cs | 8 ++--
.../Entities/Types/TupleType.cs | 2 +-
.../Entities/UserOperator.cs | 2 +-
.../SymbolExtensions.cs | 41 +++++++++++++------
6 files changed, 42 insertions(+), 27 deletions(-)
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs
index 298f838cfb9..3230ad699f6 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs
@@ -114,7 +114,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
if (symbol.IsStatic) trapFile.Write("static");
trapFile.WriteSubId(ContainingType);
- AddParametersToId(Context, trapFile, symbol);
+ AddParametersToId(Context, trapFile, symbol, symbol);
trapFile.Write(";constructor");
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs
index 21538a57741..77c9e2ab21d 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs
@@ -129,12 +129,12 @@ namespace Semmle.Extraction.CSharp.Entities
// Type arguments with different nullability can result in
// a constructed method with different nullability of its parameters and return type,
// so we need to create a distinct database entity for it.
- trapFile.BuildList(",", m.symbol.GetAnnotatedTypeArguments(), (ta, tb0) => { AddSignatureTypeToId(m.Context, tb0, m.symbol, ta.Symbol); trapFile.Write((int)ta.Nullability); });
+ trapFile.BuildList(",", m.symbol.GetAnnotatedTypeArguments(), (ta, tb0) => { AddSignatureTypeToId(m.Context, tb0, m.symbol, ta.Symbol, m.symbol); trapFile.Write((int)ta.Nullability); });
trapFile.Write('>');
}
}
- AddParametersToId(m.Context, trapFile, m.symbol);
+ AddParametersToId(m.Context, trapFile, m.symbol, m.symbol);
switch (m.symbol.MethodKind)
{
case MethodKind.PropertyGet:
@@ -199,12 +199,12 @@ namespace Semmle.Extraction.CSharp.Entities
/// to make the reference to #3 in the label definition #4 for
/// T valid.
///
- protected static void AddSignatureTypeToId(Context cx, TextWriter trapFile, IMethodSymbol method, ITypeSymbol type)
+ protected static void AddSignatureTypeToId(Context cx, TextWriter trapFile, IMethodSymbol method, ITypeSymbol type, ISymbol symbolBeingDefined)
{
- type.BuildTypeId(cx, trapFile, false, (cx0, tb0, type0) => AddSignatureTypeToId(cx, tb0, method, type0));
+ type.BuildTypeId(cx, trapFile, false, symbolBeingDefined, (cx0, tb0, type0, g) => AddSignatureTypeToId(cx, tb0, method, type0, g));
}
- protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethodSymbol method)
+ protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethodSymbol method, ISymbol generic)
{
trapFile.Write('(');
int index = 0;
@@ -212,13 +212,13 @@ namespace Semmle.Extraction.CSharp.Entities
if (method.MethodKind == MethodKind.ReducedExtension)
{
trapFile.WriteSeparator(",", ref index);
- AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType);
+ AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType, generic);
}
foreach (var param in method.Parameters)
{
trapFile.WriteSeparator(",", ref index);
- AddSignatureTypeToId(cx, trapFile, method, param.Type);
+ AddSignatureTypeToId(cx, trapFile, method, param.Type, generic);
switch (param.RefKind)
{
case RefKind.Out:
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs
index 4e584180c7c..5611477daf0 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs
@@ -111,7 +111,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
- symbol.BuildTypeId(Context, trapFile, true, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub)));
+ symbol.BuildTypeId(Context, trapFile, true, symbol, (cx0, tb0, sub, g) => tb0.WriteSubId(Create(cx0, sub)));
trapFile.Write(";type");
}
@@ -177,11 +177,11 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
- void WriteType(Context cx, TextWriter trapFile, ITypeSymbol symbol)
+ void WriteType(Context cx, TextWriter trapFile, ITypeSymbol symbol, ISymbol symbolBeingDefined)
{
- symbol.BuildTypeId(cx, trapFile, false, WriteType);
+ symbol.BuildTypeId(cx, trapFile, false, symbolBeingDefined, WriteType);
}
- WriteType(Context, trapFile, referencedType.symbol);
+ WriteType(Context, trapFile, referencedType.symbol, referencedType.symbol);
trapFile.Write(";typeRef");
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs
index e0adee16142..4f5e5f68d40 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs
@@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
- symbol.BuildTypeId(Context, trapFile, false, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub)));
+ symbol.BuildTypeId(Context, trapFile, false, symbol, (cx0, tb0, sub, g) => tb0.WriteSubId(Create(cx0, sub)));
trapFile.Write(";tuple");
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs
index 2a64a29fa0d..9c94058af1f 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs
@@ -51,7 +51,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
- AddSignatureTypeToId(Context, trapFile, symbol, symbol.ReturnType); // Needed for op_explicit(), which differs only by return type.
+ AddSignatureTypeToId(Context, trapFile, symbol, symbol.ReturnType, symbol); // Needed for op_explicit(), which differs only by return type.
trapFile.Write(' ');
BuildMethodId(this, trapFile);
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs
index c871da6e59a..7acfc502720 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs
@@ -131,7 +131,7 @@ namespace Semmle.Extraction.CSharp
/// The extraction context.
/// The trap builder used to store the result.
/// The action to apply to syntactic sub terms of this type.
- public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, bool prefix, Action subTermAction)
+ public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, bool prefix, ISymbol SymbolBeingDefined, Action subTermAction)
{
if (type.SpecialType != SpecialType.None && !(type is INamedTypeSymbol n && n.IsGenericType))
{
@@ -150,7 +150,7 @@ namespace Semmle.Extraction.CSharp
{
case TypeKind.Array:
var array = (IArrayTypeSymbol)type;
- subTermAction(cx, trapFile, array.ElementType);
+ subTermAction(cx, trapFile, array.ElementType, SymbolBeingDefined);
array.BuildArraySuffix(trapFile);
return;
case TypeKind.Class:
@@ -160,15 +160,30 @@ namespace Semmle.Extraction.CSharp
case TypeKind.Delegate:
case TypeKind.Error:
var named = (INamedTypeSymbol)type;
- named.BuildNamedTypeId(cx, trapFile, prefix, subTermAction);
+ named.BuildNamedTypeId(cx, trapFile, prefix, SymbolBeingDefined, subTermAction);
return;
case TypeKind.Pointer:
var ptr = (IPointerTypeSymbol)type;
- subTermAction(cx, trapFile, ptr.PointedAtType);
+ subTermAction(cx, trapFile, ptr.PointedAtType, SymbolBeingDefined);
trapFile.Write('*');
return;
case TypeKind.TypeParameter:
var tp = (ITypeParameterSymbol)type;
+ if (!SymbolEqualityComparer.Default.Equals(tp.ContainingSymbol, SymbolBeingDefined))
+ {
+ switch (tp.TypeParameterKind)
+ {
+ case TypeParameterKind.Method:
+ var method = Method.Create(cx, (IMethodSymbol)tp.ContainingSymbol);
+ trapFile.WriteSubId(method);
+ trapFile.Write('_');
+ break;
+ case TypeParameterKind.Type:
+ subTermAction(cx, trapFile, tp.ContainingType, SymbolBeingDefined);
+ trapFile.Write('_');
+ break;
+ }
+ }
trapFile.Write(tp.Name);
return;
case TypeKind.Dynamic:
@@ -211,7 +226,7 @@ namespace Semmle.Extraction.CSharp
trapFile.Write("::");
}
- static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, bool prefixAssembly, Action subTermAction)
+ static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, bool prefixAssembly, ISymbol symbolBeingDefined, Action subTermAction)
{
if (named.ContainingAssembly is null) prefixAssembly = false;
@@ -223,7 +238,7 @@ namespace Semmle.Extraction.CSharp
{
trapFile.Write(f.Name);
trapFile.Write(":");
- subTermAction(cx, tb0, f.Type);
+ subTermAction(cx, tb0, f.Type, symbolBeingDefined);
}
);
trapFile.Write(")");
@@ -232,7 +247,7 @@ namespace Semmle.Extraction.CSharp
if (named.ContainingType != null)
{
- subTermAction(cx, trapFile, named.ContainingType);
+ subTermAction(cx, trapFile, named.ContainingType, symbolBeingDefined);
trapFile.Write('.');
}
else if (named.ContainingNamespace != null)
@@ -254,14 +269,14 @@ namespace Semmle.Extraction.CSharp
}
else
{
- subTermAction(cx, trapFile, named.ConstructedFrom);
+ subTermAction(cx, trapFile, named.ConstructedFrom, symbolBeingDefined);
trapFile.Write('<');
// Encode the nullability of the type arguments in the label.
// Type arguments with different nullability can result in
// a constructed type with different nullability of its members and methods,
// so we need to create a distinct database entity for it.
trapFile.BuildList(",", named.GetAnnotatedTypeArguments(),
- (ta, tb0) => subTermAction(cx, tb0, ta.Symbol)
+ (ta, tb0) => subTermAction(cx, tb0, ta.Symbol, symbolBeingDefined)
);
trapFile.Write('>');
}
@@ -273,16 +288,16 @@ namespace Semmle.Extraction.CSharp
trapFile.Write('.');
}
- static void BuildAnonymousName(this ITypeSymbol type, Context cx, TextWriter trapFile, Action subTermAction, bool includeParamName)
+ static void BuildAnonymousName(this ITypeSymbol type, Context cx, TextWriter trapFile, Action subTermAction, bool includeParamName)
{
var buildParam = includeParamName
? (prop, tb0) =>
{
tb0.Write(prop.Name);
tb0.Write(' ');
- subTermAction(cx, tb0, prop.Type);
+ subTermAction(cx, tb0, prop.Type, null);
}
- : (Action)((prop, tb0) => subTermAction(cx, tb0, prop.Type));
+ : (Action)((prop, tb0) => subTermAction(cx, tb0, prop.Type, null));
int memberCount = type.GetMembers().OfType().Count();
int hackTypeNumber = memberCount == 1 ? 1 : 0;
trapFile.Write("<>__AnonType");
@@ -354,7 +369,7 @@ namespace Semmle.Extraction.CSharp
if (namedType.IsAnonymousType)
{
- namedType.BuildAnonymousName(cx, trapFile, (cx0, tb0, sub) => sub.BuildDisplayName(cx0, tb0), false);
+ namedType.BuildAnonymousName(cx, trapFile, (cx0, tb0, sub, _) => sub.BuildDisplayName(cx0, tb0), false);
}
trapFile.Write(namedType.Name);
From abf6be6030f6709e2066ba7bf343dbb789ba02e2 Mon Sep 17 00:00:00 2001
From: Calum Grant
Date: Wed, 12 Feb 2020 16:23:48 +0000
Subject: [PATCH 0082/1298] C#: Avoid qualifying explicit interface
implementations.
---
.../Entities/Method.cs | 11 ++++---
.../Entities/Types/NamedType.cs | 8 ++---
.../Entities/Types/TupleType.cs | 2 +-
.../SymbolExtensions.cs | 32 +++++++++++++++----
.../library-tests/aliases/aliases2.expected | 6 ++++
.../csharp8/NullableRefTypes.expected | 4 +--
6 files changed, 43 insertions(+), 20 deletions(-)
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs
index 77c9e2ab21d..384ef46dbe9 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs
@@ -204,7 +204,7 @@ namespace Semmle.Extraction.CSharp.Entities
type.BuildTypeId(cx, trapFile, false, symbolBeingDefined, (cx0, tb0, type0, g) => AddSignatureTypeToId(cx, tb0, method, type0, g));
}
- protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethodSymbol method, ISymbol generic)
+ protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethodSymbol method, ISymbol symbolBeingDefined)
{
trapFile.Write('(');
int index = 0;
@@ -212,13 +212,13 @@ namespace Semmle.Extraction.CSharp.Entities
if (method.MethodKind == MethodKind.ReducedExtension)
{
trapFile.WriteSeparator(",", ref index);
- AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType, generic);
+ AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType, symbolBeingDefined);
}
foreach (var param in method.Parameters)
{
trapFile.WriteSeparator(",", ref index);
- AddSignatureTypeToId(cx, trapFile, method, param.Type, generic);
+ AddSignatureTypeToId(cx, trapFile, method, param.Type, symbolBeingDefined);
switch (param.RefKind)
{
case RefKind.Out:
@@ -241,9 +241,10 @@ namespace Semmle.Extraction.CSharp.Entities
public static void AddExplicitInterfaceQualifierToId(Context cx, System.IO.TextWriter trapFile, IEnumerable explicitInterfaceImplementations)
{
- if (explicitInterfaceImplementations.Any())
+ foreach (var i in explicitInterfaceImplementations)
{
- trapFile.AppendList(",", explicitInterfaceImplementations.Select(impl => cx.CreateEntity(impl.ContainingType)));
+ trapFile.Write(';');
+ i.ContainingType.BuildNestedTypeId(cx, trapFile, null);
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs
index 5611477daf0..25145520aee 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs
@@ -111,7 +111,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
- symbol.BuildTypeId(Context, trapFile, true, symbol, (cx0, tb0, sub, g) => tb0.WriteSubId(Create(cx0, sub)));
+ symbol.BuildTypeId(Context, trapFile, true, symbol, (cx0, tb0, sub, _) => tb0.WriteSubId(Create(cx0, sub)));
trapFile.Write(";type");
}
@@ -177,11 +177,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
- void WriteType(Context cx, TextWriter trapFile, ITypeSymbol symbol, ISymbol symbolBeingDefined)
- {
- symbol.BuildTypeId(cx, trapFile, false, symbolBeingDefined, WriteType);
- }
- WriteType(Context, trapFile, referencedType.symbol, referencedType.symbol);
+ referencedType.symbol.BuildNestedTypeId(Context, trapFile, referencedType.symbol);
trapFile.Write(";typeRef");
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs
index 4f5e5f68d40..b7e38fd88f4 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs
@@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
- symbol.BuildTypeId(Context, trapFile, false, symbol, (cx0, tb0, sub, g) => tb0.WriteSubId(Create(cx0, sub)));
+ symbol.BuildTypeId(Context, trapFile, false, symbol, (cx0, tb0, sub, _) => tb0.WriteSubId(Create(cx0, sub)));
trapFile.Write(";tuple");
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs
index 7acfc502720..17a493771c6 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs
@@ -122,6 +122,24 @@ namespace Semmle.Extraction.CSharp
}
}
+ ///
+ /// Write the identifier for the symbol to the trapfile .
+ /// If any nested types are found in the identifier, then they are written out explicitly, without
+ /// prefixing the assembly ID.
+ ///
+ /// The type to write.
+ /// The extraction context.
+ /// The trap file to write to.
+ /// The outer symbol being defined (to avoid recursive ids).
+ public static void BuildNestedTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, ISymbol symbolBeingDefined)
+ {
+ void WriteType(Context cx, TextWriter trapFile, ITypeSymbol symbol, ISymbol symbolBeingDefined)
+ {
+ symbol.BuildTypeId(cx, trapFile, false, symbolBeingDefined, WriteType);
+ }
+ WriteType(cx, trapFile, type, symbolBeingDefined);
+ }
+
///
/// Constructs a unique string for this type symbol.
///
@@ -130,8 +148,10 @@ namespace Semmle.Extraction.CSharp
///
/// The extraction context.
/// The trap builder used to store the result.
+ /// Whether to prefix the type ID with the assembly ID.
+ /// The outer symbol being defined (to avoid recursive ids).
/// The action to apply to syntactic sub terms of this type.
- public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, bool prefix, ISymbol SymbolBeingDefined, Action subTermAction)
+ public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, bool prefix, ISymbol symbolBeingDefined, Action subTermAction)
{
if (type.SpecialType != SpecialType.None && !(type is INamedTypeSymbol n && n.IsGenericType))
{
@@ -150,7 +170,7 @@ namespace Semmle.Extraction.CSharp
{
case TypeKind.Array:
var array = (IArrayTypeSymbol)type;
- subTermAction(cx, trapFile, array.ElementType, SymbolBeingDefined);
+ subTermAction(cx, trapFile, array.ElementType, symbolBeingDefined);
array.BuildArraySuffix(trapFile);
return;
case TypeKind.Class:
@@ -160,16 +180,16 @@ namespace Semmle.Extraction.CSharp
case TypeKind.Delegate:
case TypeKind.Error:
var named = (INamedTypeSymbol)type;
- named.BuildNamedTypeId(cx, trapFile, prefix, SymbolBeingDefined, subTermAction);
+ named.BuildNamedTypeId(cx, trapFile, prefix, symbolBeingDefined, subTermAction);
return;
case TypeKind.Pointer:
var ptr = (IPointerTypeSymbol)type;
- subTermAction(cx, trapFile, ptr.PointedAtType, SymbolBeingDefined);
+ subTermAction(cx, trapFile, ptr.PointedAtType, symbolBeingDefined);
trapFile.Write('*');
return;
case TypeKind.TypeParameter:
var tp = (ITypeParameterSymbol)type;
- if (!SymbolEqualityComparer.Default.Equals(tp.ContainingSymbol, SymbolBeingDefined))
+ if (!SymbolEqualityComparer.Default.Equals(tp.ContainingSymbol, symbolBeingDefined))
{
switch (tp.TypeParameterKind)
{
@@ -179,7 +199,7 @@ namespace Semmle.Extraction.CSharp
trapFile.Write('_');
break;
case TypeParameterKind.Type:
- subTermAction(cx, trapFile, tp.ContainingType, SymbolBeingDefined);
+ subTermAction(cx, trapFile, tp.ContainingType, symbolBeingDefined);
trapFile.Write('_');
break;
}
diff --git a/csharp/ql/test/library-tests/aliases/aliases2.expected b/csharp/ql/test/library-tests/aliases/aliases2.expected
index 45870c5dda2..05fad62d6a8 100644
--- a/csharp/ql/test/library-tests/aliases/aliases2.expected
+++ b/csharp/ql/test/library-tests/aliases/aliases2.expected
@@ -1,3 +1,9 @@
| Program.cs:18:21:18:22 | c1 | Assembly1.dll:0:0:0:0 | Class |
+| Program.cs:18:21:18:22 | c1 | Assembly2.dll:0:0:0:0 | Class |
+| Program.cs:18:21:18:22 | c1 | Program.cs:10:7:10:11 | Class |
+| Program.cs:19:21:19:22 | c2 | Assembly1.dll:0:0:0:0 | Class |
| Program.cs:19:21:19:22 | c2 | Assembly2.dll:0:0:0:0 | Class |
+| Program.cs:19:21:19:22 | c2 | Program.cs:10:7:10:11 | Class |
+| Program.cs:20:15:20:16 | c3 | Assembly1.dll:0:0:0:0 | Class |
+| Program.cs:20:15:20:16 | c3 | Assembly2.dll:0:0:0:0 | Class |
| Program.cs:20:15:20:16 | c3 | Program.cs:10:7:10:11 | Class |
diff --git a/csharp/ql/test/library-tests/csharp8/NullableRefTypes.expected b/csharp/ql/test/library-tests/csharp8/NullableRefTypes.expected
index db4f3c6fb5d..ff888cc88dd 100644
--- a/csharp/ql/test/library-tests/csharp8/NullableRefTypes.expected
+++ b/csharp/ql/test/library-tests/csharp8/NullableRefTypes.expected
@@ -241,9 +241,9 @@ expressionTypes
| NullableRefTypes.cs:17:29:17:32 | null | null |
| NullableRefTypes.cs:18:31:18:34 | this access | MyClass! |
| NullableRefTypes.cs:19:33:19:36 | this access | MyClass! |
-| NullableRefTypes.cs:26:44:26:53 | throw ... | MyClass![]! |
+| NullableRefTypes.cs:26:44:26:53 | throw ... | MyClass?[]! |
| NullableRefTypes.cs:26:50:26:53 | null | null |
-| NullableRefTypes.cs:27:44:27:53 | throw ... | MyClass![]! |
+| NullableRefTypes.cs:27:44:27:53 | throw ... | MyClass?[]! |
| NullableRefTypes.cs:27:50:27:53 | null | null |
| NullableRefTypes.cs:30:21:30:24 | null | null |
| NullableRefTypes.cs:31:20:31:23 | this access | MyClass! |
From 7af5f038aba000e5467416f87b5024f97acebcd8 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Tue, 7 Apr 2020 14:02:53 +0200
Subject: [PATCH 0083/1298] Python: Add missing override to
ClassValue.hasAttribute
I was considering if this was actually something different than
Value.hasAttribute, and the names were just accidentially the same. But after
looking at the definition for Value, I'm happy about marking this as an
override (I did not test whether it was neede though):
```codeql
class Value extends TObject {
...
/** Holds if this value has the attribute `name` */
predicate hasAttribute(string name) { this.(ObjectInternal).hasAttribute(name) }
```
---
python/ql/src/semmle/python/objects/ObjectAPI.qll | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll
index 9772a77ed8b..a3d6431b448 100644
--- a/python/ql/src/semmle/python/objects/ObjectAPI.qll
+++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll
@@ -540,10 +540,10 @@ class ClassValue extends Value {
Value declaredAttribute(string name) { Types::declaredAttribute(this, name, result, _) }
/**
- * Holds if this class has the attribute `name`, including
- * attributes declared by super classes.
+ * Holds if this class has the attribute `name`, including attributes
+ * declared by super classes.
*/
- predicate hasAttribute(string name) { this.getMro().declares(name) }
+ override predicate hasAttribute(string name) { this.getMro().declares(name) }
/**
* Holds if this class declares the attribute `name`,
From d56284fe8fc0aeadf674bc4e118aa85de54b8228 Mon Sep 17 00:00:00 2001
From: Mathias Vorreiter Pedersen
Date: Tue, 7 Apr 2020 16:00:40 +0200
Subject: [PATCH 0084/1298] C++: Move added flow from simpleLocalFlowStep to
simpleInstructionLocalFlowStep and remove flow that could cause field
conflation
---
.../cpp/ir/dataflow/internal/DataFlowUtil.qll | 17 +++++------------
.../dataflow/dataflow-tests/test_diff.expected | 4 +++-
.../dataflow/dataflow-tests/test_ir.expected | 4 ----
.../dataflow/taint-tests/test_diff.expected | 4 +---
.../dataflow/taint-tests/test_ir.expected | 4 ----
.../literals/literals/literals.expected | 8 ++++----
6 files changed, 13 insertions(+), 28 deletions(-)
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
index a7a5f9d6d86..91c089959dc 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
@@ -385,13 +385,6 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr
*/
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction())
- or
- exists(LoadInstruction load, ChiInstruction chi |
- not chi.isResultConflated() and
- nodeTo.asInstruction() = load and
- nodeFrom.asInstruction() = chi and
- load.getSourceValueOperand().getAnyDef() = chi
- )
}
private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction iTo) {
@@ -417,13 +410,13 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction
//
// Flow through the partial operand belongs in the taint-tracking libraries
// for now.
- // TODO: To capture flow from a partial definition of an object (i.e., a field write) to the object
- // we add dataflow through partial chi operands, but only if the chi node is not the chi node for all
- // aliased memory.
- iTo.getAnOperand().(ChiPartialOperand).getDef() = iFrom and not iTo.isResultConflated()
- or
iTo.getAnOperand().(ChiTotalOperand).getDef() = iFrom
or
+ exists(ChiInstruction chi | iFrom = chi |
+ not chi.isResultConflated() and
+ iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = chi
+ )
+ or
// Flow through modeled functions
modelFlow(iFrom, iTo)
}
diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected
index 11c5acc30fc..71630f892f5 100644
--- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected
+++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected
@@ -2,7 +2,6 @@
| BarrierGuard.cpp:60:11:60:16 | BarrierGuard.cpp:62:14:62:14 | AST only |
| clang.cpp:12:9:12:20 | clang.cpp:22:8:22:20 | AST only |
| clang.cpp:28:27:28:32 | clang.cpp:30:27:30:34 | AST only |
-| clang.cpp:28:27:28:32 | clang.cpp:31:27:31:28 | IR only |
| clang.cpp:39:42:39:47 | clang.cpp:41:18:41:19 | IR only |
| dispatch.cpp:16:37:16:42 | dispatch.cpp:32:16:32:24 | IR only |
| dispatch.cpp:16:37:16:42 | dispatch.cpp:40:15:40:23 | IR only |
@@ -46,6 +45,9 @@
| test.cpp:359:13:359:18 | test.cpp:365:10:365:14 | AST only |
| test.cpp:373:13:373:18 | test.cpp:369:10:369:14 | AST only |
| test.cpp:373:13:373:18 | test.cpp:375:10:375:14 | AST only |
+| test.cpp:382:48:382:54 | test.cpp:385:8:385:10 | AST only |
+| test.cpp:388:53:388:59 | test.cpp:392:8:392:10 | AST only |
+| test.cpp:388:53:388:59 | test.cpp:394:10:394:12 | AST only |
| test.cpp:399:7:399:9 | test.cpp:401:8:401:10 | AST only |
| test.cpp:405:7:405:9 | test.cpp:408:8:408:10 | AST only |
| test.cpp:416:7:416:11 | test.cpp:418:8:418:12 | AST only |
diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected
index f4e072d1905..275cbabc075 100644
--- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected
+++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected
@@ -12,7 +12,6 @@
| clang.cpp:18:8:18:19 | (const int *)... | clang.cpp:12:9:12:20 | sourceArray1 |
| clang.cpp:18:8:18:19 | sourceArray1 | clang.cpp:12:9:12:20 | sourceArray1 |
| clang.cpp:29:27:29:28 | m1 | clang.cpp:28:27:28:32 | call to source |
-| clang.cpp:31:27:31:28 | m2 | clang.cpp:28:27:28:32 | call to source |
| clang.cpp:37:10:37:11 | m2 | clang.cpp:34:32:34:37 | call to source |
| clang.cpp:41:18:41:19 | m2 | clang.cpp:39:42:39:47 | call to source |
| clang.cpp:45:17:45:18 | m2 | clang.cpp:43:35:43:40 | call to source |
@@ -62,9 +61,6 @@
| test.cpp:266:12:266:12 | x | test.cpp:265:22:265:27 | call to source |
| test.cpp:289:14:289:14 | x | test.cpp:305:17:305:22 | call to source |
| test.cpp:318:7:318:7 | x | test.cpp:314:4:314:9 | call to source |
-| test.cpp:385:8:385:10 | tmp | test.cpp:382:48:382:54 | source1 |
-| test.cpp:392:8:392:10 | tmp | test.cpp:388:53:388:59 | source1 |
-| test.cpp:394:10:394:12 | tmp | test.cpp:388:53:388:59 | source1 |
| test.cpp:450:9:450:22 | (statement expression) | test.cpp:449:26:449:32 | source1 |
| test.cpp:461:8:461:12 | local | test.cpp:449:26:449:32 | source1 |
| true_upon_entry.cpp:13:8:13:8 | x | true_upon_entry.cpp:9:11:9:16 | call to source |
diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected
index ffe098d6063..329a0bb6ecc 100644
--- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected
+++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected
@@ -17,15 +17,13 @@
| taint.cpp:93:11:93:11 | taint.cpp:71:22:71:27 | AST only |
| taint.cpp:94:11:94:11 | taint.cpp:72:7:72:12 | AST only |
| taint.cpp:109:7:109:13 | taint.cpp:105:12:105:17 | IR only |
-| taint.cpp:110:7:110:13 | taint.cpp:105:12:105:17 | IR only |
-| taint.cpp:111:7:111:13 | taint.cpp:106:12:106:17 | IR only |
-| taint.cpp:112:7:112:13 | taint.cpp:106:12:106:17 | IR only |
| taint.cpp:130:7:130:9 | taint.cpp:127:8:127:13 | IR only |
| taint.cpp:137:7:137:9 | taint.cpp:120:11:120:16 | AST only |
| taint.cpp:173:8:173:13 | taint.cpp:164:19:164:24 | AST only |
| taint.cpp:181:8:181:9 | taint.cpp:185:11:185:16 | AST only |
| taint.cpp:195:7:195:7 | taint.cpp:192:23:192:28 | AST only |
| taint.cpp:195:7:195:7 | taint.cpp:193:6:193:6 | AST only |
+| taint.cpp:216:7:216:7 | taint.cpp:207:6:207:11 | AST only |
| taint.cpp:229:3:229:6 | taint.cpp:223:10:223:15 | AST only |
| taint.cpp:233:8:233:8 | taint.cpp:223:10:223:15 | AST only |
| taint.cpp:236:3:236:6 | taint.cpp:223:10:223:15 | AST only |
diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected
index e6f138e6283..b0107791e61 100644
--- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected
+++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected
@@ -2,9 +2,6 @@
| taint.cpp:16:8:16:14 | source1 | taint.cpp:12:22:12:27 | call to source |
| taint.cpp:17:8:17:16 | ++ ... | taint.cpp:12:22:12:27 | call to source |
| taint.cpp:109:7:109:13 | access to array | taint.cpp:105:12:105:17 | call to source |
-| taint.cpp:110:7:110:13 | access to array | taint.cpp:105:12:105:17 | call to source |
-| taint.cpp:111:7:111:13 | access to array | taint.cpp:106:12:106:17 | call to source |
-| taint.cpp:112:7:112:13 | access to array | taint.cpp:106:12:106:17 | call to source |
| taint.cpp:129:7:129:9 | * ... | taint.cpp:120:11:120:16 | call to source |
| taint.cpp:130:7:130:9 | * ... | taint.cpp:127:8:127:13 | call to source |
| taint.cpp:134:7:134:9 | * ... | taint.cpp:120:11:120:16 | call to source |
@@ -13,7 +10,6 @@
| taint.cpp:168:8:168:14 | tainted | taint.cpp:164:19:164:24 | call to source |
| taint.cpp:210:7:210:7 | x | taint.cpp:207:6:207:11 | call to source |
| taint.cpp:215:7:215:7 | x | taint.cpp:207:6:207:11 | call to source |
-| taint.cpp:216:7:216:7 | y | taint.cpp:207:6:207:11 | call to source |
| taint.cpp:250:8:250:8 | a | taint.cpp:223:10:223:15 | call to source |
| taint.cpp:280:7:280:7 | t | taint.cpp:275:6:275:11 | call to source |
| taint.cpp:289:7:289:7 | t | taint.cpp:275:6:275:11 | call to source |
diff --git a/cpp/ql/test/library-tests/literals/literals/literals.expected b/cpp/ql/test/library-tests/literals/literals/literals.expected
index a3fd43a7f04..4e640c9b2dc 100644
--- a/cpp/ql/test/library-tests/literals/literals/literals.expected
+++ b/cpp/ql/test/library-tests/literals/literals/literals.expected
@@ -2,10 +2,10 @@
| literals.c:3:13:3:16 | 1.0 |
| literals.c:4:13:4:16 | 1.0 |
| literals.c:5:13:5:16 | 1.0 |
-| literals.c:6:13:6:16 | (0.0,1.0i) |
-| literals.c:7:13:7:16 | (0.0,1.0i) |
-| literals.c:8:13:8:16 | (0.0,1.0i) |
-| literals.c:9:13:9:16 | (0.0,1.0i) |
+| literals.c:6:13:6:16 | (1.0,1.0i) |
+| literals.c:7:13:7:16 | (1.0,1.0i) |
+| literals.c:8:13:8:16 | (1.0,1.0i) |
+| literals.c:9:13:9:16 | (1.0,1.0i) |
| literals.c:10:13:10:16 | 1.0 |
| literals.c:11:13:11:16 | 1.0 |
| literals.c:12:13:12:16 | 1.0 |
From 1f496d3c6b3fd3f61f096910a748b789ba503592 Mon Sep 17 00:00:00 2001
From: Asger Feldthaus
Date: Tue, 7 Apr 2020 19:02:46 +0100
Subject: [PATCH 0085/1298] JS: Add CapturedVariableNode
---
.../ql/src/semmle/javascript/Variables.qll | 13 +++++
.../semmle/javascript/dataflow/DataFlow.qll | 50 +++++++++++++++----
2 files changed, 52 insertions(+), 11 deletions(-)
diff --git a/javascript/ql/src/semmle/javascript/Variables.qll b/javascript/ql/src/semmle/javascript/Variables.qll
index 5c5c3e3f115..bef027d6fbd 100644
--- a/javascript/ql/src/semmle/javascript/Variables.qll
+++ b/javascript/ql/src/semmle/javascript/Variables.qll
@@ -317,6 +317,19 @@ class LocalVariable extends Variable {
else result = d.getContainer()
)
}
+
+ /**
+ * Gets the location of a declaration of this variable.
+ *
+ * If the variable has multiple declarations, an arbitrary one is used.
+ * If it has no declaration, the location of its declaring scope is used.
+ */
+ Location getLocation() {
+ result = min(Location loc | loc = getADeclaration().getLocation() | loc order by loc.getStartLine(), loc.getStartColumn() )
+ or
+ not exists(getADeclaration()) and
+ result = getDeclaringContainer().getLocation()
+ }
}
/** A local variable that is not captured. */
diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll
index 5d7ce03e467..d4d7e3bff16 100644
--- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll
+++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll
@@ -27,6 +27,7 @@ module DataFlow {
private newtype TNode =
TValueNode(AST::ValueNode nd) or
TSsaDefNode(SsaDefinition d) or
+ TCapturedVariableNode(LocalVariable v) { v.isCaptured() } or
TPropNode(@property p) or
TRestPatternNode(DestructuringPattern dp, Expr rest) { rest = dp.getRest() } or
TDestructuringPatternNode(DestructuringPattern dp) or
@@ -1221,6 +1222,29 @@ module DataFlow {
}
}
+ /**
+ * A data flow node representing a captured variable.
+ */
+ private class CapturedVariableNode extends Node, TCapturedVariableNode {
+ LocalVariable variable;
+
+ CapturedVariableNode() { this = TCapturedVariableNode(variable) }
+
+ override BasicBlock getBasicBlock() {
+ result = variable.getDeclaringContainer().getStartBB()
+ }
+
+ override predicate hasLocationInfo(
+ string filepath, int startline, int startcolumn, int endline, int endcolumn
+ ) {
+ variable.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ }
+
+ override string toString() {
+ result = variable.getName()
+ }
+ }
+
/**
* Gets the data flow node corresponding to `nd`.
*
@@ -1434,19 +1458,23 @@ module DataFlow {
or
immediateFlowStep(pred, succ)
or
+ // From an assignment or implicit initialization of a captured variable to its flow-insensitive node.
+ exists(SsaDefinition predDef |
+ pred = TSsaDefNode(predDef) and
+ succ = TCapturedVariableNode(predDef.getSourceVariable())
+ |
+ predDef instanceof SsaExplicitDefinition or
+ predDef instanceof SsaImplicitInit
+ )
+ or
+ // From a captured variable node to its flow-sensitive capture nodes
+ exists(SsaVariableCapture ssaCapture |
+ pred = TCapturedVariableNode(ssaCapture.getSourceVariable()) and
+ succ = TSsaDefNode(ssaCapture)
+ )
+ or
// Flow through implicit SSA nodes
exists(SsaImplicitDefinition ssa | succ = TSsaDefNode(ssa) |
- // from any explicit definition or implicit init of a captured variable into
- // the capturing definition
- exists(SsaSourceVariable v, SsaDefinition predDef |
- v = ssa.(SsaVariableCapture).getSourceVariable() and
- predDef.getSourceVariable() = v and
- pred = TSsaDefNode(predDef)
- |
- predDef instanceof SsaExplicitDefinition or
- predDef instanceof SsaImplicitInit
- )
- or
// from the inputs of phi and pi nodes into the node itself
pred = TSsaDefNode(ssa.(SsaPseudoDefinition).getAnInput().getDefinition())
)
From 4c7d413fa478329807686e6ea768752d4fb8cad5 Mon Sep 17 00:00:00 2001
From: Calum Grant
Date: Tue, 7 Apr 2020 19:58:48 +0100
Subject: [PATCH 0086/1298] C#: Address review comment.
---
.../Semmle.Extraction.CSharp/Entities/Constructor.cs | 2 +-
.../extractor/Semmle.Extraction.CSharp/Entities/Method.cs | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs
index 3230ad699f6..298f838cfb9 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs
@@ -114,7 +114,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
if (symbol.IsStatic) trapFile.Write("static");
trapFile.WriteSubId(ContainingType);
- AddParametersToId(Context, trapFile, symbol, symbol);
+ AddParametersToId(Context, trapFile, symbol);
trapFile.Write(";constructor");
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs
index 384ef46dbe9..7fe73cde06d 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs
@@ -134,7 +134,7 @@ namespace Semmle.Extraction.CSharp.Entities
}
}
- AddParametersToId(m.Context, trapFile, m.symbol, m.symbol);
+ AddParametersToId(m.Context, trapFile, m.symbol);
switch (m.symbol.MethodKind)
{
case MethodKind.PropertyGet:
@@ -204,7 +204,7 @@ namespace Semmle.Extraction.CSharp.Entities
type.BuildTypeId(cx, trapFile, false, symbolBeingDefined, (cx0, tb0, type0, g) => AddSignatureTypeToId(cx, tb0, method, type0, g));
}
- protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethodSymbol method, ISymbol symbolBeingDefined)
+ protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethodSymbol method)
{
trapFile.Write('(');
int index = 0;
@@ -212,13 +212,13 @@ namespace Semmle.Extraction.CSharp.Entities
if (method.MethodKind == MethodKind.ReducedExtension)
{
trapFile.WriteSeparator(",", ref index);
- AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType, symbolBeingDefined);
+ AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType, method);
}
foreach (var param in method.Parameters)
{
trapFile.WriteSeparator(",", ref index);
- AddSignatureTypeToId(cx, trapFile, method, param.Type, symbolBeingDefined);
+ AddSignatureTypeToId(cx, trapFile, method, param.Type, method);
switch (param.RefKind)
{
case RefKind.Out:
From 0d65db148fbd25b73ee6ea0fe5821ee88f6c6e4c Mon Sep 17 00:00:00 2001
From: Rebecca Valentine
Date: Tue, 7 Apr 2020 21:14:25 -0700
Subject: [PATCH 0087/1298] Python: ObjectAPI to ValueAPI:
IterReturnsNonIterator: Adds preliminary modernization
---
python/ql/src/Functions/IterReturnsNonIterator.ql | 10 +++++-----
.../Functions/general/IterReturnsNonIterator.expected | 8 ++++----
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/python/ql/src/Functions/IterReturnsNonIterator.ql b/python/ql/src/Functions/IterReturnsNonIterator.ql
index 67db4e89aa3..20e3d311fa8 100644
--- a/python/ql/src/Functions/IterReturnsNonIterator.ql
+++ b/python/ql/src/Functions/IterReturnsNonIterator.ql
@@ -12,17 +12,17 @@
import python
-ClassObject return_type(FunctionObject f) {
+ClassValue return_type(FunctionValue f) {
exists(ControlFlowNode n, Return ret |
- ret.getScope() = f.getFunction() and
+ ret.getScope() = f.getScope() and
ret.getValue() = n.getNode() and
- n.refersTo(_, result, _)
+ result = n.pointsTo().getClass()
)
}
-from ClassObject iterable, FunctionObject iter, ClassObject iterator
+from ClassValue iterable, FunctionValue iter, ClassValue iterator
where
- iter = iterable.lookupAttribute("__iter__") and
+ iter = iterable.lookup("__iter__") and
iterator = return_type(iter) and
not iterator.isIterator()
select iterator,
diff --git a/python/ql/test/query-tests/Functions/general/IterReturnsNonIterator.expected b/python/ql/test/query-tests/Functions/general/IterReturnsNonIterator.expected
index 2393f18674a..5f0c2c4797c 100644
--- a/python/ql/test/query-tests/Functions/general/IterReturnsNonIterator.expected
+++ b/python/ql/test/query-tests/Functions/general/IterReturnsNonIterator.expected
@@ -1,4 +1,4 @@
-| file://:Compiled Code:0:0:0:0 | builtin-class object | Class object is returned as an iterator (by $@) but does not fully implement the iterator interface. | protocols.py:16:5:16:23 | Function __iter__ | __iter__ |
-| protocols.py:20:1:20:26 | class IteratorMissingNext | Class IteratorMissingNext is returned as an iterator (by $@) but does not fully implement the iterator interface. | protocols.py:22:5:22:23 | Function __iter__ | __iter__ |
-| protocols.py:20:1:20:26 | class IteratorMissingNext | Class IteratorMissingNext is returned as an iterator (by $@) but does not fully implement the iterator interface. | protocols.py:27:5:27:23 | Function __iter__ | __iter__ |
-| protocols.py:30:1:30:26 | class IteratorMissingIter | Class IteratorMissingIter is returned as an iterator (by $@) but does not fully implement the iterator interface. | protocols.py:40:5:40:23 | Function __iter__ | __iter__ |
+| file://:0:0:0:0 | builtin-class object | Class object is returned as an iterator (by $@) but does not fully implement the iterator interface. | protocols.py:16:5:16:23 | Function X.__iter__ | __iter__ |
+| protocols.py:20:1:20:26 | class IteratorMissingNext | Class IteratorMissingNext is returned as an iterator (by $@) but does not fully implement the iterator interface. | protocols.py:22:5:22:23 | Function IteratorMissingNext.__iter__ | __iter__ |
+| protocols.py:20:1:20:26 | class IteratorMissingNext | Class IteratorMissingNext is returned as an iterator (by $@) but does not fully implement the iterator interface. | protocols.py:27:5:27:23 | Function IterableMissingNext.__iter__ | __iter__ |
+| protocols.py:30:1:30:26 | class IteratorMissingIter | Class IteratorMissingIter is returned as an iterator (by $@) but does not fully implement the iterator interface. | protocols.py:40:5:40:23 | Function IterableMissingIter.__iter__ | __iter__ |
From dacbc1376ca4e34938e779c027c980f7c45ae5b8 Mon Sep 17 00:00:00 2001
From: Felicity Chapman
Date: Wed, 8 Apr 2020 10:36:04 +0100
Subject: [PATCH 0088/1298] Update some out of date information
---
cpp/ql/src/Options.qll | 2 +-
cpp/ql/src/semmle/code/cpp/Compilation.qll | 4 ++--
cpp/ql/src/semmle/code/cpp/dataflow/RecursionPrevention.qll | 2 +-
docs/language/README.rst | 2 +-
docs/language/learn-ql/ql-training.rst | 2 +-
docs/language/learn-ql/writing-queries/path-queries.rst | 2 +-
docs/language/learn-ql/writing-queries/query-help.rst | 2 +-
docs/language/ql-handbook/annotations.rst | 6 +++---
docs/language/ql-handbook/language.rst | 2 +-
.../ql-training/slide-snippets/intro-ql-general.rst | 6 +++---
docs/query-help-style-guide.md | 2 +-
javascript/documentation/flow-summaries.rst | 4 ++--
12 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/cpp/ql/src/Options.qll b/cpp/ql/src/Options.qll
index 353d012e339..3c7e320dff6 100644
--- a/cpp/ql/src/Options.qll
+++ b/cpp/ql/src/Options.qll
@@ -4,7 +4,7 @@
*
* By default they fall back to the reasonable defaults provided in
* `DefaultOptions.qll`, but by modifying this file, you can customize
- * the standard Semmle analyses to give better results for your project.
+ * the standard analyses to give better results for your project.
*/
import cpp
diff --git a/cpp/ql/src/semmle/code/cpp/Compilation.qll b/cpp/ql/src/semmle/code/cpp/Compilation.qll
index 02d962844c8..c5fdcbed5f9 100644
--- a/cpp/ql/src/semmle/code/cpp/Compilation.qll
+++ b/cpp/ql/src/semmle/code/cpp/Compilation.qll
@@ -21,9 +21,9 @@ private predicate idOf(@compilation x, int y) = equivalenceRelation(id/2)(x, y)
* Three things happen to each file during a compilation:
*
* 1. The file is compiled by a real compiler, such as gcc or VC.
- * 2. The file is parsed by Semmle's C++ front-end.
+ * 2. The file is parsed by the CodeQL C++ front-end.
* 3. The parsed representation is converted to database tables by
- * Semmle's extractor.
+ * the CodeQL extractor.
*
* This class provides CPU and elapsed time information for steps 2 and 3,
* but not for step 1.
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/RecursionPrevention.qll b/cpp/ql/src/semmle/code/cpp/dataflow/RecursionPrevention.qll
index 626e50925f9..2d8b52f8622 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/RecursionPrevention.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/RecursionPrevention.qll
@@ -1,6 +1,6 @@
/**
* DEPRECATED: Recursion through `DataFlow::Configuration` is impossible in
- * Semmle Core 1.17 and above. There is no need for this module because it's
+ * any supported tooling. There is no need for this module because it's
* impossible to accidentally depend on recursion through
* `DataFlow::Configuration` in current releases.
*
diff --git a/docs/language/README.rst b/docs/language/README.rst
index 48beeed5791..ecc9d4d0c09 100644
--- a/docs/language/README.rst
+++ b/docs/language/README.rst
@@ -109,7 +109,7 @@ examples, see the `template slide deck `__.
There, you can also find the documentation for the CodeQL CLI,
the CodeQL extension for Visual Studio Code, and LGTM Enterprise.
diff --git a/docs/language/learn-ql/ql-training.rst b/docs/language/learn-ql/ql-training.rst
index d0eac290a56..5b014ca72fc 100644
--- a/docs/language/learn-ql/ql-training.rst
+++ b/docs/language/learn-ql/ql-training.rst
@@ -32,7 +32,7 @@ We recommend that you download `CodeQL for Visual Studio Code `__, `C# `__, `Java `__, `JavaScript `__, and `Python `__ to see examples of the queries included in the Semmle tools.
+- Take a look at the path queries for `C/C++ `__, `C# `__, `Java `__, `JavaScript `__, and `Python `__ to see examples of these queries.
- Explore the `query cookbooks `__ to see how to access the basic language elements contained in the CodeQL libraries.
- For a full list of resources to help you learn CodeQL, including beginner tutorials and language-specific examples, visit `Learning CodeQL `__.
diff --git a/docs/language/learn-ql/writing-queries/query-help.rst b/docs/language/learn-ql/writing-queries/query-help.rst
index 0ab52f845a8..76c8c442db9 100644
--- a/docs/language/learn-ql/writing-queries/query-help.rst
+++ b/docs/language/learn-ql/writing-queries/query-help.rst
@@ -63,7 +63,7 @@ Section-level elements are used to group the information in the help file into s
+--------------------+------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
| ``section`` | ``title`` Title of the section | Any block element | General-purpose section with a heading defined by the ``title`` attribute. |
+--------------------+------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
-| ``semmleNotes`` | None | Any block element | Semmle-specific notes about the query. This section is used only for queries that implement a rule defined by a third party. Default heading. |
+| ``semmleNotes`` | None | Any block element | Implementation notes about the query. This section is used only for queries that implement a rule defined by a third party. Default heading. |
+--------------------+------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
Block elements
diff --git a/docs/language/ql-handbook/annotations.rst b/docs/language/ql-handbook/annotations.rst
index 816b5ea5310..9177a4197b6 100644
--- a/docs/language/ql-handbook/annotations.rst
+++ b/docs/language/ql-handbook/annotations.rst
@@ -249,7 +249,7 @@ Compiler pragmas
The following compiler pragmas affect the compilation and optimization of queries. You
should avoid using these annotations unless you experience significant performance issues.
-Before adding pragmas to your code, contact Semmle to describe the performance problems.
+Before adding pragmas to your code, contact GitHub to describe the performance problems.
That way we can suggest the best solution for your problem, and take it into account when
improving the QL optimizer.
@@ -292,7 +292,7 @@ optimization on a predicate.
This kind of optimization involves taking information from the context of a predicate
:ref:`call ` and pushing it into the body of a predicate. This is usually
beneficial, so you shouldn't use the ``pragma[nomagic]`` annotation unless recommended to do so
-by Semmle.
+by GitHub.
Note that ``nomagic`` implies ``noinline``.
@@ -303,7 +303,7 @@ The ``pragma[noopt]`` annotation is used to prevent the QL optimizer from optimi
predicate, except when it's absolutely necessary for compilation and evaluation to work.
This is rarely necessary and you should not use the ``pragma[noopt]`` annotation unless
-recommended to do so by Semmle, for example, to help resolve performance issues.
+recommended to do so by GitHub, for example, to help resolve performance issues.
When you use this annotation, be aware of the following issues:
diff --git a/docs/language/ql-handbook/language.rst b/docs/language/ql-handbook/language.rst
index 5bb7370d11c..1446e18a4f8 100644
--- a/docs/language/ql-handbook/language.rst
+++ b/docs/language/ql-handbook/language.rst
@@ -1002,7 +1002,7 @@ For casts between the primitive ``float`` and ``int`` types, the above rule mean
Postfix casts
~~~~~~~~~~~~~
-*Available from Semmle 1.9.4 onward.* A postfix cast is a primary expression followed by a dot and then a class or primitive type in parentheses:
+A postfix cast is a primary expression followed by a dot and then a class or primitive type in parentheses:
::
diff --git a/docs/language/ql-training/slide-snippets/intro-ql-general.rst b/docs/language/ql-training/slide-snippets/intro-ql-general.rst
index 2dc64517465..f03c0300e25 100644
--- a/docs/language/ql-training/slide-snippets/intro-ql-general.rst
+++ b/docs/language/ql-training/slide-snippets/intro-ql-general.rst
@@ -101,7 +101,7 @@ Analysis overview
.. note::
- Semmle’s analysis works by extracting a queryable database from your project. For compiled languages, Semmle’s tools observe an ordinary build of the source code. Each time a compiler is invoked to process a source file, a copy of that file is made, and all relevant information about the source code (syntactic data about the abstract syntax tree, semantic data like name binding and type information, data on the operation of the C preprocessor, etc.) is collected. For interpreted languages, the extractor gathers similar information by running directly on the source code. Multi-language code bases are analyzed one language at a time.
+ CodeQL analysis works by extracting a queryable database from your project. For compiled languages, the tools observe an ordinary build of the source code. Each time a compiler is invoked to process a source file, a copy of that file is made, and all relevant information about the source code (syntactic data about the abstract syntax tree, semantic data like name binding and type information, data on the operation of the C preprocessor, etc.) is collected. For interpreted languages, the extractor gathers similar information by running directly on the source code. Multi-language code bases are analyzed one language at a time.
Once the extraction finishes, all this information is collected into a single `CodeQL database `__, which is then ready to query, possibly on a different machine. A copy of the source files, made at the time the database was created, is also included in the CodeQL database so analysis results can be displayed at the correct location in the code. The database schema is (source) language specific.
@@ -129,7 +129,7 @@ QL is:
- All common logic connectives are available, including quantifiers like ``exist``, which can also introduce new variables.
- The language is declarative–the user focuses on stating what they would like to find, and leaves the details of how to evaluate the query to the engine.
- - The object-oriented layer allows Semmle to distribute rich standard libraries for program analysis. These model the common AST node types, control flow and name lookup, and define further layers on top–for example control flow or data flow analysis. The `standard CodeQL libraries and queries `__ ship as source and can be inspected by the user, and new abstractions are readily defined.
- - The database generated by Semmle’s tools is treated as read-only; queries cannot insert new data into it, though they can inspect its contents in various ways.
+ - The object-oriented layer allows us to develop rich standard libraries for program analysis. These model the common AST node types, control flow and name lookup, and define further layers on top–for example control flow or data flow analysis. The `standard CodeQL libraries and queries `__ ship as source and can be inspected by the user, and new abstractions are readily defined.
+ - The database generated by the CodeQL tools is treated as read-only; queries cannot insert new data into it, though they can inspect its contents in various ways.
You can start writing running queries on open source projects in the `query console `__ on LGTM.com. You can also download CodeQL databases from LGTM.com to query locally, by `running queries in your IDE `__.
diff --git a/docs/query-help-style-guide.md b/docs/query-help-style-guide.md
index 58e2d93f95e..7ddda7c60de 100644
--- a/docs/query-help-style-guide.md
+++ b/docs/query-help-style-guide.md
@@ -2,7 +2,7 @@
## Introduction
-When you contribute a new query to Semmle/ql for inclusion in the standard queries, or add a custom query for analysis in LGTM, you should also write a query help file. This file provides detailed information about the purpose and use of the query, which is available to users in LGTM (for example [here](https://lgtm.com/rules/1506093386171/)) and on the query homepages:
+When you contribute a new [supported query](supported-queries.md) to this repository, or add a custom query for analysis in LGTM, you should also write a query help file. This file provides detailed information about the purpose and use of the query, which is available to users in LGTM (for example [here](https://lgtm.com/rules/1506093386171/)) and on the query homepages:
* [C/C++ queries](https://help.semmle.com/wiki/display/CCPPOBJ/)
* [C# queries](https://help.semmle.com/wiki/display/CSHARP/)
diff --git a/javascript/documentation/flow-summaries.rst b/javascript/documentation/flow-summaries.rst
index edd6cb027b0..6a6c482f69d 100644
--- a/javascript/documentation/flow-summaries.rst
+++ b/javascript/documentation/flow-summaries.rst
@@ -5,7 +5,7 @@ Overview
--------
This document presents an approach for running information flow analyses (such as the standard
-Semmle security queries) on an application that depends on one or more npm packages. Instead of
+security queries) on an application that depends on one or more npm packages. Instead of
installing the npm packages during the snapshot build and analyzing them together with application
code, we analyze each package in isolation and compute *flow summaries* that record information
about any sources, sinks and flow steps contributed by the package's API. These flow summaries
@@ -41,7 +41,7 @@ If the value of ``p`` can be controlled by an untrusted user, this would allow t
folders, which may not be desirable.
By analyzing the application code base together with the source code for the ``mkdirp`` package,
-Semmle's default path injection analysis would be able to track taint through the call to ``mkdirp`` into its
+the default path injection analysis would be able to track taint through the call to ``mkdirp`` into its
implementation, which ultimately uses built-in Node.js file system APIs to create the folder. Since
the path injection analysis has built-in models of these APIs it would then be able to spot and flag this
vulnerability.
From 9db6b8f1e2b63c1602ae6dcfe3d0aedaf01cf728 Mon Sep 17 00:00:00 2001
From: Felicity Chapman
Date: Wed, 8 Apr 2020 11:42:30 +0100
Subject: [PATCH 0089/1298] Update
docs/language/learn-ql/writing-queries/query-help.rst
Co-Authored-By: James Fletcher <42464962+jf205@users.noreply.github.com>
---
docs/language/learn-ql/writing-queries/query-help.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/language/learn-ql/writing-queries/query-help.rst b/docs/language/learn-ql/writing-queries/query-help.rst
index 76c8c442db9..44ef01cccf7 100644
--- a/docs/language/learn-ql/writing-queries/query-help.rst
+++ b/docs/language/learn-ql/writing-queries/query-help.rst
@@ -63,7 +63,7 @@ Section-level elements are used to group the information in the help file into s
+--------------------+------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
| ``section`` | ``title`` Title of the section | Any block element | General-purpose section with a heading defined by the ``title`` attribute. |
+--------------------+------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
-| ``semmleNotes`` | None | Any block element | Implementation notes about the query. This section is used only for queries that implement a rule defined by a third party. Default heading. |
+| ``semmleNotes`` | None | Any block element | Implementation notes about the query. This section is used only for queries that implement a rule defined by a third party. Default heading. |
+--------------------+------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
Block elements
From 07d913125691f9386d85ece5db547f10f1258717 Mon Sep 17 00:00:00 2001
From: Felicity Chapman
Date: Wed, 8 Apr 2020 12:14:40 +0100
Subject: [PATCH 0090/1298] Update
docs/language/learn-ql/writing-queries/query-help.rst
Co-Authored-By: Shati Patel <42641846+shati-patel@users.noreply.github.com>
---
docs/language/learn-ql/writing-queries/query-help.rst | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/docs/language/learn-ql/writing-queries/query-help.rst b/docs/language/learn-ql/writing-queries/query-help.rst
index 8795569d5bc..89cad6528c6 100644
--- a/docs/language/learn-ql/writing-queries/query-help.rst
+++ b/docs/language/learn-ql/writing-queries/query-help.rst
@@ -84,8 +84,7 @@ The following elements are optional child elements of the ``section``, ``example
| | | ``height`` Optional, height of the image. | | |
| | | ``width`` Optional, the width of the image. | | |
+----------------+----------------------------------------------------------+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
- | ``include`` | ``src`` The query help file to include. | None | Include a query help file at the location of this element. See :ref:`Query help inclusion <
- -inclusion>` below for more information. |
+ | ``include`` | ``src`` The query help file to include. | None | Include a query help file at the location of this element. See :ref:`Query help inclusion ` below for more information. |
+----------------+----------------------------------------------------------+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ``ol`` | None | ``li`` | Display an ordered list. See List elements below. |
+----------------+----------------------------------------------------------+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
From ac3acb9187e53108bf5e733a73176531800c58f0 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Wed, 8 Apr 2020 14:44:25 +0200
Subject: [PATCH 0091/1298] Python: Add more deprecated annotations
These classes/predicates are not used by anything in our codebase, and is using
deprecated classes/predicates, so I think it's safe to assume they should also
have been marked with the deprecated annotation.
Changes the QL compiler warnings with:
-WARNING: Type Configuration has been deprecated and may be removed in future (/home/rasmus/code/ql/python/ql/src/semmle/python/dataflow/TaintTracking.qll:663,50-63)
-WARNING: Type Configuration has been deprecated and may be removed in future (/home/rasmus/code/ql/python/ql/src/semmle/python/dataflow/TaintTracking.qll:666,19-32)
-WARNING: Type Configuration has been deprecated and may be removed in future (/home/rasmus/code/ql/python/ql/src/semmle/python/dataflow/TaintTracking.qll:671,19-32)
-WARNING: Type Configuration has been deprecated and may be removed in future (/home/rasmus/code/ql/python/ql/src/semmle/python/dataflow/TaintTracking.qll:733,16-39)
-WARNING: Type CustomPointsToAttribute has been deprecated and may be removed in future (/home/rasmus/code/ql/python/ql/src/semmle/python/types/Extensions.qll:181,28-51)
-WARNING: Type CustomPointsToFact has been deprecated and may be removed in future (/home/rasmus/code/ql/python/ql/src/semmle/python/types/Extensions.qll:155,60-78)
-WARNING: Type CustomPointsToFact has been deprecated and may be removed in future (/home/rasmus/code/ql/python/ql/src/semmle/python/types/Extensions.qll:159,19-37)
-WARNING: Type CustomPointsToFact has been deprecated and may be removed in future (/home/rasmus/code/ql/python/ql/src/semmle/python/types/Extensions.qll:41,33-51)
+WARNING: Type CustomPointsToFact has been deprecated and may be removed in future (/home/rasmus/code/ql/python/ql/src/semmle/python/types/Extensions.qll:41,44-62)
---
python/ql/src/semmle/python/dataflow/TaintTracking.qll | 4 ++--
python/ql/src/semmle/python/types/Extensions.qll | 6 +++---
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/python/ql/src/semmle/python/dataflow/TaintTracking.qll b/python/ql/src/semmle/python/dataflow/TaintTracking.qll
index 88ef3c4e4fc..fe21ced8d50 100755
--- a/python/ql/src/semmle/python/dataflow/TaintTracking.qll
+++ b/python/ql/src/semmle/python/dataflow/TaintTracking.qll
@@ -659,7 +659,7 @@ module DataFlow {
}
}
- private class ConfigurationAdapter extends TaintTracking::Configuration {
+ deprecated private class ConfigurationAdapter extends TaintTracking::Configuration {
ConfigurationAdapter() { this instanceof Configuration }
override predicate isSource(DataFlow::Node node, TaintKind kind) {
@@ -727,7 +727,7 @@ module DataFlow {
}
}
-private class DataFlowType extends TaintKind {
+deprecated private class DataFlowType extends TaintKind {
DataFlowType() {
this = "Data flow" and
exists(DataFlow::Configuration c)
diff --git a/python/ql/src/semmle/python/types/Extensions.qll b/python/ql/src/semmle/python/types/Extensions.qll
index 7e1e7c5ab85..78ad15d7fbd 100644
--- a/python/ql/src/semmle/python/types/Extensions.qll
+++ b/python/ql/src/semmle/python/types/Extensions.qll
@@ -38,7 +38,7 @@ abstract deprecated class CustomPointsToFact extends @py_flow_node {
}
/* For backwards compatibility */
-class FinalCustomPointsToFact = CustomPointsToFact;
+deprecated class FinalCustomPointsToFact = CustomPointsToFact;
abstract deprecated class CustomPointsToOriginFact extends CustomPointsToFact {
abstract predicate pointsTo(Object value, ClassObject cls);
@@ -151,7 +151,7 @@ class ReModulePointToExtension extends PointsToExtension {
private predicate pointsTo_helper(Context context) { context.appliesTo(this) }
}
-private class BackwardCompatiblePointToExtension extends PointsToExtension {
+deprecated private class BackwardCompatiblePointToExtension extends PointsToExtension {
BackwardCompatiblePointToExtension() { this instanceof CustomPointsToFact }
override predicate pointsTo(Context context, ObjectInternal value, ControlFlowNode origin) {
@@ -174,7 +174,7 @@ private class BackwardCompatiblePointToExtension extends PointsToExtension {
}
}
-private predicate additionalAttribute(
+deprecated private predicate additionalAttribute(
ObjectInternal owner, string name, ObjectInternal value, ControlFlowNode origin
) {
exists(Object obj, ClassObject cls |
From 32c04ad76556f2b9e11c490da475a01dd26acba7 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Wed, 8 Apr 2020 16:46:33 +0200
Subject: [PATCH 0092/1298] Python: Use getAbsolutePath() instead of deprecated
getName()
---
python/ql/src/external/CodeDuplication.qll | 2 +-
python/ql/src/external/DefectFilter.qll | 4 ++--
python/ql/src/external/VCS.qll | 2 +-
python/ql/src/semmle/python/filters/GeneratedCode.qll | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/python/ql/src/external/CodeDuplication.qll b/python/ql/src/external/CodeDuplication.qll
index c195d16ae6a..d558ee7e8a7 100644
--- a/python/ql/src/external/CodeDuplication.qll
+++ b/python/ql/src/external/CodeDuplication.qll
@@ -66,7 +66,7 @@ class Copy extends @duplication_or_similarity {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
- sourceFile().getName() = filepath and
+ sourceFile().getAbsolutePath() = filepath and
startline = sourceStartLine() and
startcolumn = sourceStartColumn() and
endline = sourceEndLine() and
diff --git a/python/ql/src/external/DefectFilter.qll b/python/ql/src/external/DefectFilter.qll
index 6d5f75510cf..38419dee2ec 100644
--- a/python/ql/src/external/DefectFilter.qll
+++ b/python/ql/src/external/DefectFilter.qll
@@ -26,7 +26,7 @@ class DefectResult extends int {
/** Gets the file in which this query result was reported. */
File getFile() {
- exists(string path | defectResults(this, _, path, _, _, _, _, _) and result.getName() = path)
+ exists(string path | defectResults(this, _, path, _, _, _, _, _) and result.getAbsolutePath() = path)
}
/** Gets the file path in which this query result was reported. */
@@ -54,7 +54,7 @@ class DefectResult extends int {
/** Gets the URL corresponding to the location of this query result. */
string getURL() {
result =
- "file://" + getFile().getName() + ":" + getStartLine() + ":" + getStartColumn() + ":" +
+ "file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn() + ":" +
getEndLine() + ":" + getEndColumn()
}
}
diff --git a/python/ql/src/external/VCS.qll b/python/ql/src/external/VCS.qll
index 2d03f7d882d..0212dbfbd24 100644
--- a/python/ql/src/external/VCS.qll
+++ b/python/ql/src/external/VCS.qll
@@ -23,7 +23,7 @@ class Commit extends @svnentry {
string getMessage() { svnentrymsg(this, result) }
string getAnAffectedFilePath(string action) {
- exists(File rawFile | svnaffectedfiles(this, rawFile, action) | result = rawFile.getName())
+ exists(File rawFile | svnaffectedfiles(this, rawFile, action) | result = rawFile.getAbsolutePath())
}
string getAnAffectedFilePath() { result = getAnAffectedFilePath(_) }
diff --git a/python/ql/src/semmle/python/filters/GeneratedCode.qll b/python/ql/src/semmle/python/filters/GeneratedCode.qll
index 411cb558e7e..5b1721945da 100644
--- a/python/ql/src/semmle/python/filters/GeneratedCode.qll
+++ b/python/ql/src/semmle/python/filters/GeneratedCode.qll
@@ -170,7 +170,7 @@ string from_mako_import(Module m) {
/** File generated by Google's protobuf tool. */
class ProtobufGeneratedFile extends SpecificGeneratedFile {
ProtobufGeneratedFile() {
- this.getName().regexpMatch(".*_pb2?.py") and
+ this.getAbsolutePath().regexpMatch(".*_pb2?.py") and
exists(Module m | m.getFile() = this |
exists(ImportExpr imp | imp.getEnclosingModule() = m |
imp.getImportedModuleName() = "google.net.proto2.python.public"
From a2440f0fcd879965c95fab28f89fe429d8a3b268 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Wed, 8 Apr 2020 16:53:19 +0200
Subject: [PATCH 0093/1298] Python: Modernise semmle/python/dataflow/Files.qll
---
python/ql/src/semmle/python/dataflow/Files.qll | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/python/ql/src/semmle/python/dataflow/Files.qll b/python/ql/src/semmle/python/dataflow/Files.qll
index 651b7a93850..467a8bec29e 100644
--- a/python/ql/src/semmle/python/dataflow/Files.qll
+++ b/python/ql/src/semmle/python/dataflow/Files.qll
@@ -11,7 +11,7 @@ class OpenFileConfiguration extends TaintTracking::Configuration {
OpenFileConfiguration() { this = "Open file configuration" }
override predicate isSource(DataFlow::Node src, TaintKind kind) {
- theOpenFunction().(FunctionObject).getACall() = src.asCfgNode() and
+ src.asCfgNode() = Value::named("open").getACall() and
kind instanceof OpenFile
}
From 47934310efe81f30a2aa17efa70b90752425ec8a Mon Sep 17 00:00:00 2001
From: Asger Feldthaus
Date: Wed, 8 Apr 2020 19:58:36 +0100
Subject: [PATCH 0094/1298] JS: Hide captured nodes in path explanations
---
.../ql/src/semmle/javascript/dataflow/Configuration.qll | 3 +++
.../ql/src/semmle/javascript/dataflow/DataFlow.qll | 9 +++++++++
2 files changed, 12 insertions(+)
diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll
index 1406c19a518..e57c0764000 100644
--- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll
+++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll
@@ -1462,6 +1462,9 @@ class MidPathNode extends PathNode, MkMidNode {
or
// Skip the synthetic 'this' node, as a ThisExpr will be the next node anyway
nd = DataFlow::thisNode(_)
+ or
+ // Skip captured variable nodes as the successor will be a use of that variable anyway.
+ nd = DataFlow::capturedVariableNode(_)
}
}
diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll
index d4d7e3bff16..18365e16770 100644
--- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll
+++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll
@@ -1245,6 +1245,15 @@ module DataFlow {
}
}
+ /**
+ * INTERNAL. DO NOT USE.
+ *
+ * Gets a data flow node representing the given captured variable.
+ */
+ Node capturedVariableNode(LocalVariable variable) {
+ result = TCapturedVariableNode(variable)
+ }
+
/**
* Gets the data flow node corresponding to `nd`.
*
From e1a680cd867b454f34f9f7d7a5cd940e7a17ffaf Mon Sep 17 00:00:00 2001
From: luchua-bc
Date: Wed, 8 Apr 2020 19:10:35 -0400
Subject: [PATCH 0095/1298] Address improper URL authorization
---
.../CWE-939/IncorrectURLVerification.java | 17 +++++
.../CWE-939/IncorrectURLVerification.qhelp | 30 +++++++++
.../CWE-939/IncorrectURLVerification.ql | 64 +++++++++++++++++++
3 files changed, 111 insertions(+)
create mode 100644 java/ql/src/experimental/CWE-939/IncorrectURLVerification.java
create mode 100644 java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp
create mode 100644 java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql
diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.java b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.java
new file mode 100644
index 00000000000..f7b42b483af
--- /dev/null
+++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.java
@@ -0,0 +1,17 @@
+public boolean shouldOverrideUrlLoading(WebView view, String url) {
+ {
+ Uri uri = Uri.parse(url);
+ // BAD: partial domain match, which allows an attacker to register a domain like myexample.com to circumvent the verification
+ if (uri.getHost() != null && uri.getHost().endsWith("example.com")) {
+ return false;
+ }
+ }
+
+ {
+ Uri uri = Uri.parse(url);
+ // GOOD: full domain match
+ if (uri.getHost() != null && uri.getHost().endsWith(".example.com")) {
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp
new file mode 100644
index 00000000000..d1526456c98
--- /dev/null
+++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp
@@ -0,0 +1,30 @@
+
+
+
+
+Apps that rely on URL Parsing to verify that a given URL is pointing to a trust server may be susceptible to many different ways to get URL parsing and verification wrong, which allows an attacker to register a fake site to break the access control.
+
+
+
+Verify the whole host and domain (FQDN) or check endsWith dot+domain.
+
+
+
+The following example shows two ways of verify host domain. In the 'BAD' case,
+verification is implemented as partial domain match. In the 'GOOD' case, full domain is verified.
+
+
+
+
+
+Common Android app vulnerabilities from Sebastian Porst of Google
+
+
+Common Android app vulnerabilities from bugcrowd
+
+CWE 939
+
+
+
\ No newline at end of file
diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql
new file mode 100644
index 00000000000..eed077ea0b9
--- /dev/null
+++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql
@@ -0,0 +1,64 @@
+/**
+ * @id java/incorrect-url-verification
+ * @name Insertion of sensitive information into log files
+ * @description Apps that rely on URL parsing to verify that a given URL is pointing to a trusted server are susceptible to wrong ways of URL parsing and verification.
+ * @kind problem
+ * @tags security
+ * external/cwe-939
+ */
+
+import java
+import semmle.code.java.dataflow.FlowSources
+import semmle.code.java.dataflow.TaintTracking
+import DataFlow
+import PathGraph
+
+
+/**
+ * The Java class `android.net.Uri` and `java.net.URL`.
+ */
+class Uri extends RefType {
+ Uri() {
+ hasQualifiedName("android.net", "Uri") or
+ hasQualifiedName("java.net", "URL")
+ }
+}
+
+/**
+ * The method `getHost()` declared in `android.net.Uri` and `java.net.URL`.
+ */
+class UriGetHostMethod extends Method {
+ UriGetHostMethod() {
+ getDeclaringType() instanceof Uri and
+ hasName("getHost") and
+ getNumberOfParameters() = 0
+ }
+}
+
+/**
+ * A library method that acts like `String.format` by formatting a number of
+ * its arguments according to a format string.
+ */
+class HostVerificationMethodAccess extends MethodAccess {
+ HostVerificationMethodAccess() {
+ (
+
+ this.getMethod().hasName("endsWith") or
+ this.getMethod().hasName("contains") or
+ this.getMethod().hasName("indexOf")
+ ) and
+ this.getMethod().getNumberOfParameters() = 1 and
+ (
+ this.getArgument(0).(StringLiteral).getRepresentedString().charAt(0) != "." or //string constant comparison
+ this.getArgument(0).(AddExpr).getLeftOperand().(VarAccess).getVariable().getAnAssignedValue().(StringLiteral).getRepresentedString().charAt(0) != "." or //var1+var2, check var1 starts with "."
+ this.getArgument(0).(AddExpr).getLeftOperand().(StringLiteral).getRepresentedString().charAt(0) != "." or //"."+var2, check string constant "."
+ exists (MethodAccess ma | this.getArgument(0) = ma and ma.getMethod().hasName("getString") and ma.getArgument(0).toString().indexOf("R.string") = 0) or //res.getString(R.string.key)
+ this.getArgument(0).(VarAccess).getVariable().getAnAssignedValue().(StringLiteral).getRepresentedString().charAt(0) != "." //check variable starts with "."
+ )
+ }
+}
+
+from UriGetHostMethod um, MethodAccess uma, HostVerificationMethodAccess hma
+where hma.getQualifier() = uma and uma.getMethod() = um
+select "Potentially improper URL verification with $@ in $@ having $@.",
+ hma, hma.getFile(), hma.getArgument(0), "user-provided value"
\ No newline at end of file
From b7f2d32fb0a3578d1022535940fd658151d42d21 Mon Sep 17 00:00:00 2001
From: luchua-bc
Date: Wed, 8 Apr 2020 19:16:22 -0400
Subject: [PATCH 0096/1298] Address improper URL authorization
---
.../CWE-939/IncorrectURLVerification.java | 30 +++++++++----------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.java b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.java
index f7b42b483af..1c06f05bc7e 100644
--- a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.java
+++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.java
@@ -1,17 +1,17 @@
public boolean shouldOverrideUrlLoading(WebView view, String url) {
- {
- Uri uri = Uri.parse(url);
- // BAD: partial domain match, which allows an attacker to register a domain like myexample.com to circumvent the verification
- if (uri.getHost() != null && uri.getHost().endsWith("example.com")) {
- return false;
- }
- }
+ {
+ Uri uri = Uri.parse(url);
+ // BAD: partial domain match, which allows an attacker to register a domain like myexample.com to circumvent the verification
+ if (uri.getHost() != null && uri.getHost().endsWith("example.com")) {
+ return false;
+ }
+ }
- {
- Uri uri = Uri.parse(url);
- // GOOD: full domain match
- if (uri.getHost() != null && uri.getHost().endsWith(".example.com")) {
- return false;
- }
- }
-}
\ No newline at end of file
+ {
+ Uri uri = Uri.parse(url);
+ // GOOD: full domain match
+ if (uri.getHost() != null && uri.getHost().endsWith(".example.com")) {
+ return false;
+ }
+ }
+}
From d9f81b082b395f5177262c2c1ea3029bc7df7460 Mon Sep 17 00:00:00 2001
From: Asger Feldthaus
Date: Thu, 9 Apr 2020 07:45:00 +0100
Subject: [PATCH 0097/1298] JS: Autoformat
---
javascript/ql/src/semmle/javascript/Variables.qll | 7 ++++++-
.../ql/src/semmle/javascript/dataflow/DataFlow.qll | 12 +++---------
2 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/javascript/ql/src/semmle/javascript/Variables.qll b/javascript/ql/src/semmle/javascript/Variables.qll
index bef027d6fbd..238ecef4687 100644
--- a/javascript/ql/src/semmle/javascript/Variables.qll
+++ b/javascript/ql/src/semmle/javascript/Variables.qll
@@ -325,7 +325,12 @@ class LocalVariable extends Variable {
* If it has no declaration, the location of its declaring scope is used.
*/
Location getLocation() {
- result = min(Location loc | loc = getADeclaration().getLocation() | loc order by loc.getStartLine(), loc.getStartColumn() )
+ result =
+ min(Location loc |
+ loc = getADeclaration().getLocation()
+ |
+ loc order by loc.getStartLine(), loc.getStartColumn()
+ )
or
not exists(getADeclaration()) and
result = getDeclaringContainer().getLocation()
diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll
index 18365e16770..8b014a2d00c 100644
--- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll
+++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll
@@ -1230,9 +1230,7 @@ module DataFlow {
CapturedVariableNode() { this = TCapturedVariableNode(variable) }
- override BasicBlock getBasicBlock() {
- result = variable.getDeclaringContainer().getStartBB()
- }
+ override BasicBlock getBasicBlock() { result = variable.getDeclaringContainer().getStartBB() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
@@ -1240,9 +1238,7 @@ module DataFlow {
variable.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
- override string toString() {
- result = variable.getName()
- }
+ override string toString() { result = variable.getName() }
}
/**
@@ -1250,9 +1246,7 @@ module DataFlow {
*
* Gets a data flow node representing the given captured variable.
*/
- Node capturedVariableNode(LocalVariable variable) {
- result = TCapturedVariableNode(variable)
- }
+ Node capturedVariableNode(LocalVariable variable) { result = TCapturedVariableNode(variable) }
/**
* Gets the data flow node corresponding to `nd`.
From 25d5cc78cb8a065f2409bf311c1efcdcaeced3e2 Mon Sep 17 00:00:00 2001
From: Asger Feldthaus
Date: Thu, 9 Apr 2020 09:18:26 +0100
Subject: [PATCH 0098/1298] JS: Use entry location instead of whole container
---
javascript/ql/src/semmle/javascript/Variables.qll | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/javascript/ql/src/semmle/javascript/Variables.qll b/javascript/ql/src/semmle/javascript/Variables.qll
index 238ecef4687..ede33788841 100644
--- a/javascript/ql/src/semmle/javascript/Variables.qll
+++ b/javascript/ql/src/semmle/javascript/Variables.qll
@@ -322,7 +322,7 @@ class LocalVariable extends Variable {
* Gets the location of a declaration of this variable.
*
* If the variable has multiple declarations, an arbitrary one is used.
- * If it has no declaration, the location of its declaring scope is used.
+ * If it has no declaration, the entry point of its declaring container is used.
*/
Location getLocation() {
result =
@@ -333,7 +333,7 @@ class LocalVariable extends Variable {
)
or
not exists(getADeclaration()) and
- result = getDeclaringContainer().getLocation()
+ result = getDeclaringContainer().getEntry().getLocation()
}
}
From c070416fbe0e6e4b0966ada924156e7a0b10c030 Mon Sep 17 00:00:00 2001
From: Asger Feldthaus
Date: Thu, 9 Apr 2020 12:24:11 +0100
Subject: [PATCH 0099/1298] JS: Update test output
---
.../library-tests/DataFlow/flowStep.expected | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/javascript/ql/test/library-tests/DataFlow/flowStep.expected b/javascript/ql/test/library-tests/DataFlow/flowStep.expected
index 4bb0eabd7f6..fbc30cb0ec0 100644
--- a/javascript/ql/test/library-tests/DataFlow/flowStep.expected
+++ b/javascript/ql/test/library-tests/DataFlow/flowStep.expected
@@ -13,10 +13,11 @@
| sources.js:11:12:11:18 | key | sources.js:11:32:11:34 | key |
| sources.js:11:14:11:16 | key | sources.js:11:12:11:18 | key |
| tst2.ts:1:1:1:1 | A | tst2.ts:1:18:1:18 | A |
-| tst2.ts:1:1:1:1 | A | tst2.ts:7:1:7:0 | A |
-| tst2.ts:1:8:5:1 | A | tst2.ts:7:1:7:0 | A |
+| tst2.ts:1:1:1:1 | A | tst2.ts:1:18:1:18 | A |
+| tst2.ts:1:8:5:1 | A | tst2.ts:1:18:1:18 | A |
| tst2.ts:1:8:5:1 | A | tst2.ts:11:11:11:11 | A |
| tst2.ts:1:8:5:1 | namespa ... lysed\\n} | tst2.ts:1:8:5:1 | A |
+| tst2.ts:1:18:1:18 | A | tst2.ts:7:1:7:0 | A |
| tst2.ts:2:14:2:19 | x | tst2.ts:4:3:4:3 | x |
| tst2.ts:2:18:2:19 | 42 | tst2.ts:2:14:2:19 | x |
| tst2.ts:7:1:7:0 | A | tst2.ts:8:3:8:3 | A |
@@ -26,19 +27,19 @@
| tst2.ts:11:11:11:13 | A.x | tst2.ts:11:11:11:23 | A.x as number |
| tst2.ts:13:26:13:29 | List | tst2.ts:13:26:13:37 | List |
| tst2.ts:13:39:13:38 | args | tst2.ts:13:39:13:38 | args |
-| tst.js:1:1:1:1 | x | tst.js:28:2:28:1 | x |
-| tst.js:1:1:1:1 | x | tst.js:32:1:32:0 | x |
+| tst.js:1:1:1:1 | x | tst.js:3:5:3:5 | x |
| tst.js:1:10:1:11 | fs | tst.js:1:10:1:11 | fs |
| tst.js:1:10:1:11 | fs | tst.js:7:1:7:2 | fs |
| tst.js:1:10:1:11 | fs | tst.js:22:24:22:25 | fs |
+| tst.js:3:5:3:5 | x | tst.js:28:2:28:1 | x |
+| tst.js:3:5:3:5 | x | tst.js:32:1:32:0 | x |
+| tst.js:3:5:3:10 | x | tst.js:3:5:3:5 | x |
| tst.js:3:5:3:10 | x | tst.js:8:1:8:1 | x |
| tst.js:3:5:3:10 | x | tst.js:9:2:9:2 | x |
| tst.js:3:5:3:10 | x | tst.js:10:1:10:1 | x |
| tst.js:3:5:3:10 | x | tst.js:11:1:11:1 | x |
| tst.js:3:5:3:10 | x | tst.js:11:1:11:1 | x |
| tst.js:3:5:3:10 | x | tst.js:11:1:11:1 | x |
-| tst.js:3:5:3:10 | x | tst.js:28:2:28:1 | x |
-| tst.js:3:5:3:10 | x | tst.js:32:1:32:0 | x |
| tst.js:3:9:3:10 | 42 | tst.js:3:5:3:10 | x |
| tst.js:4:5:4:12 | y | tst.js:10:4:10:4 | y |
| tst.js:4:5:4:12 | y | tst.js:11:6:11:6 | y |
@@ -75,9 +76,8 @@
| tst.js:22:5:22:25 | readFileSync | tst.js:23:1:23:12 | readFileSync |
| tst.js:22:7:22:18 | readFileSync | tst.js:22:5:22:25 | readFileSync |
| tst.js:22:24:22:25 | fs | tst.js:22:5:22:20 | { readFileSync } |
+| tst.js:25:1:25:3 | x | tst.js:3:5:3:5 | x |
| tst.js:25:1:25:3 | x | tst.js:26:1:26:1 | x |
-| tst.js:25:1:25:3 | x | tst.js:28:2:28:1 | x |
-| tst.js:25:1:25:3 | x | tst.js:32:1:32:0 | x |
| tst.js:25:1:25:3 | x | tst.js:57:7:57:7 | x |
| tst.js:25:1:25:3 | x | tst.js:58:11:58:11 | x |
| tst.js:25:1:25:3 | x | tst.js:105:1:105:1 | x |
From 5af7d5f03a060007f1d48efc07405fcbf16cc67c Mon Sep 17 00:00:00 2001
From: Henry Mercer
Date: Thu, 9 Apr 2020 13:06:53 +0100
Subject: [PATCH 0100/1298] Update README to reflect new license
Per https://github.com/Semmle/ql/pull/3205, code is now licensed under the MIT License.
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 1f77856cfc4..7d2fb59bf1a 100644
--- a/README.md
+++ b/README.md
@@ -13,4 +13,4 @@ We welcome contributions to our standard library and standard checks. Do you hav
## License
-The code in this repository is licensed under [Apache License 2.0](LICENSE) by [GitHub](https://github.com).
+The code in this repository is licensed under the [MIT License](LICENSE) by [GitHub](https://github.com).
From febbbc4423285f892e675f5f8af097df1485a1a9 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 9 Apr 2020 11:25:37 +0100
Subject: [PATCH 0101/1298] C++: Additional test cases.
---
.../TaintedAllocationSize.expected | 103 ++++++++++++++++++
.../semmle/TaintedAllocationSize/test.cpp | 48 +++++++-
2 files changed, 150 insertions(+), 1 deletion(-)
diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected
index 3847e91bbc8..4aa02918186 100644
--- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected
+++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected
@@ -69,6 +69,62 @@ edges
| test.cpp:138:19:138:32 | (const char *)... | test.cpp:142:11:142:14 | size |
| test.cpp:138:19:138:32 | (const char *)... | test.cpp:142:11:142:28 | ... * ... |
| test.cpp:138:19:138:32 | (const char *)... | test.cpp:142:11:142:28 | ... * ... |
+| test.cpp:201:9:201:12 | call to atoi | test.cpp:201:9:201:12 | call to atoi |
+| test.cpp:201:9:201:12 | call to atoi | test.cpp:201:9:201:28 | (unsigned long)... |
+| test.cpp:201:9:201:12 | call to atoi | test.cpp:201:9:201:42 | Store |
+| test.cpp:201:9:201:42 | Store | test.cpp:231:9:231:24 | call to get_tainted_size |
+| test.cpp:201:9:201:42 | Store | test.cpp:231:9:231:24 | call to get_tainted_size |
+| test.cpp:201:14:201:19 | call to getenv | test.cpp:201:9:201:12 | call to atoi |
+| test.cpp:201:14:201:19 | call to getenv | test.cpp:201:9:201:12 | call to atoi |
+| test.cpp:201:14:201:19 | call to getenv | test.cpp:201:9:201:12 | call to atoi |
+| test.cpp:201:14:201:19 | call to getenv | test.cpp:201:9:201:28 | (unsigned long)... |
+| test.cpp:201:14:201:19 | call to getenv | test.cpp:201:9:201:42 | Store |
+| test.cpp:201:14:201:27 | (const char *)... | test.cpp:201:9:201:12 | call to atoi |
+| test.cpp:201:14:201:27 | (const char *)... | test.cpp:201:9:201:12 | call to atoi |
+| test.cpp:201:14:201:27 | (const char *)... | test.cpp:201:9:201:12 | call to atoi |
+| test.cpp:201:14:201:27 | (const char *)... | test.cpp:201:9:201:28 | (unsigned long)... |
+| test.cpp:201:14:201:27 | (const char *)... | test.cpp:201:9:201:42 | Store |
+| test.cpp:206:13:206:16 | call to atoi | test.cpp:206:13:206:16 | call to atoi |
+| test.cpp:206:13:206:16 | call to atoi | test.cpp:206:13:206:32 | (unsigned long)... |
+| test.cpp:206:18:206:23 | call to getenv | test.cpp:206:13:206:16 | call to atoi |
+| test.cpp:206:18:206:23 | call to getenv | test.cpp:206:13:206:16 | call to atoi |
+| test.cpp:206:18:206:23 | call to getenv | test.cpp:206:13:206:16 | call to atoi |
+| test.cpp:206:18:206:23 | call to getenv | test.cpp:206:13:206:32 | (unsigned long)... |
+| test.cpp:206:18:206:31 | (const char *)... | test.cpp:206:13:206:16 | call to atoi |
+| test.cpp:206:18:206:31 | (const char *)... | test.cpp:206:13:206:16 | call to atoi |
+| test.cpp:206:18:206:31 | (const char *)... | test.cpp:206:13:206:16 | call to atoi |
+| test.cpp:206:18:206:31 | (const char *)... | test.cpp:206:13:206:32 | (unsigned long)... |
+| test.cpp:214:23:214:23 | s | test.cpp:215:21:215:21 | s |
+| test.cpp:214:23:214:23 | s | test.cpp:215:21:215:21 | s |
+| test.cpp:220:21:220:21 | s | test.cpp:221:21:221:21 | s |
+| test.cpp:220:21:220:21 | s | test.cpp:221:21:221:21 | s |
+| test.cpp:227:19:227:22 | call to atoi | test.cpp:227:19:227:22 | call to atoi |
+| test.cpp:227:19:227:22 | call to atoi | test.cpp:227:19:227:38 | (unsigned long)... |
+| test.cpp:227:19:227:22 | call to atoi | test.cpp:229:9:229:18 | (size_t)... |
+| test.cpp:227:19:227:22 | call to atoi | test.cpp:229:9:229:18 | local_size |
+| test.cpp:227:19:227:22 | call to atoi | test.cpp:229:9:229:18 | local_size |
+| test.cpp:227:19:227:22 | call to atoi | test.cpp:235:11:235:20 | (size_t)... |
+| test.cpp:227:19:227:22 | call to atoi | test.cpp:237:10:237:19 | (size_t)... |
+| test.cpp:227:24:227:29 | call to getenv | test.cpp:227:19:227:22 | call to atoi |
+| test.cpp:227:24:227:29 | call to getenv | test.cpp:227:19:227:22 | call to atoi |
+| test.cpp:227:24:227:29 | call to getenv | test.cpp:227:19:227:22 | call to atoi |
+| test.cpp:227:24:227:29 | call to getenv | test.cpp:227:19:227:38 | (unsigned long)... |
+| test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | (size_t)... |
+| test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | local_size |
+| test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | local_size |
+| test.cpp:227:24:227:29 | call to getenv | test.cpp:235:11:235:20 | (size_t)... |
+| test.cpp:227:24:227:29 | call to getenv | test.cpp:237:10:237:19 | (size_t)... |
+| test.cpp:227:24:227:37 | (const char *)... | test.cpp:227:19:227:22 | call to atoi |
+| test.cpp:227:24:227:37 | (const char *)... | test.cpp:227:19:227:22 | call to atoi |
+| test.cpp:227:24:227:37 | (const char *)... | test.cpp:227:19:227:22 | call to atoi |
+| test.cpp:227:24:227:37 | (const char *)... | test.cpp:227:19:227:38 | (unsigned long)... |
+| test.cpp:227:24:227:37 | (const char *)... | test.cpp:229:9:229:18 | (size_t)... |
+| test.cpp:227:24:227:37 | (const char *)... | test.cpp:229:9:229:18 | local_size |
+| test.cpp:227:24:227:37 | (const char *)... | test.cpp:229:9:229:18 | local_size |
+| test.cpp:227:24:227:37 | (const char *)... | test.cpp:235:11:235:20 | (size_t)... |
+| test.cpp:227:24:227:37 | (const char *)... | test.cpp:237:10:237:19 | (size_t)... |
+| test.cpp:235:11:235:20 | (size_t)... | test.cpp:214:23:214:23 | s |
+| test.cpp:237:10:237:19 | (size_t)... | test.cpp:220:21:220:21 | s |
nodes
| test.cpp:39:21:39:24 | argv | semmle.label | argv |
| test.cpp:39:21:39:24 | argv | semmle.label | argv |
@@ -134,6 +190,46 @@ nodes
| test.cpp:142:11:142:28 | ... * ... | semmle.label | ... * ... |
| test.cpp:142:11:142:28 | ... * ... | semmle.label | ... * ... |
| test.cpp:142:11:142:28 | ... * ... | semmle.label | ... * ... |
+| test.cpp:201:9:201:12 | call to atoi | semmle.label | call to atoi |
+| test.cpp:201:9:201:12 | call to atoi | semmle.label | call to atoi |
+| test.cpp:201:9:201:12 | call to atoi | semmle.label | call to atoi |
+| test.cpp:201:9:201:28 | (unsigned long)... | semmle.label | (unsigned long)... |
+| test.cpp:201:9:201:28 | (unsigned long)... | semmle.label | (unsigned long)... |
+| test.cpp:201:9:201:42 | Store | semmle.label | Store |
+| test.cpp:201:14:201:19 | call to getenv | semmle.label | call to getenv |
+| test.cpp:201:14:201:27 | (const char *)... | semmle.label | (const char *)... |
+| test.cpp:206:13:206:16 | call to atoi | semmle.label | call to atoi |
+| test.cpp:206:13:206:16 | call to atoi | semmle.label | call to atoi |
+| test.cpp:206:13:206:16 | call to atoi | semmle.label | call to atoi |
+| test.cpp:206:13:206:32 | (unsigned long)... | semmle.label | (unsigned long)... |
+| test.cpp:206:13:206:32 | (unsigned long)... | semmle.label | (unsigned long)... |
+| test.cpp:206:18:206:23 | call to getenv | semmle.label | call to getenv |
+| test.cpp:206:18:206:31 | (const char *)... | semmle.label | (const char *)... |
+| test.cpp:214:23:214:23 | s | semmle.label | s |
+| test.cpp:215:21:215:21 | s | semmle.label | s |
+| test.cpp:215:21:215:21 | s | semmle.label | s |
+| test.cpp:215:21:215:21 | s | semmle.label | s |
+| test.cpp:220:21:220:21 | s | semmle.label | s |
+| test.cpp:221:21:221:21 | s | semmle.label | s |
+| test.cpp:221:21:221:21 | s | semmle.label | s |
+| test.cpp:221:21:221:21 | s | semmle.label | s |
+| test.cpp:227:19:227:22 | call to atoi | semmle.label | call to atoi |
+| test.cpp:227:19:227:22 | call to atoi | semmle.label | call to atoi |
+| test.cpp:227:19:227:22 | call to atoi | semmle.label | call to atoi |
+| test.cpp:227:19:227:38 | (unsigned long)... | semmle.label | (unsigned long)... |
+| test.cpp:227:19:227:38 | (unsigned long)... | semmle.label | (unsigned long)... |
+| test.cpp:227:24:227:29 | call to getenv | semmle.label | call to getenv |
+| test.cpp:227:24:227:37 | (const char *)... | semmle.label | (const char *)... |
+| test.cpp:229:9:229:18 | (size_t)... | semmle.label | (size_t)... |
+| test.cpp:229:9:229:18 | (size_t)... | semmle.label | (size_t)... |
+| test.cpp:229:9:229:18 | local_size | semmle.label | local_size |
+| test.cpp:229:9:229:18 | local_size | semmle.label | local_size |
+| test.cpp:229:9:229:18 | local_size | semmle.label | local_size |
+| test.cpp:231:9:231:24 | call to get_tainted_size | semmle.label | call to get_tainted_size |
+| test.cpp:231:9:231:24 | call to get_tainted_size | semmle.label | call to get_tainted_size |
+| test.cpp:231:9:231:24 | call to get_tainted_size | semmle.label | call to get_tainted_size |
+| test.cpp:235:11:235:20 | (size_t)... | semmle.label | (size_t)... |
+| test.cpp:237:10:237:19 | (size_t)... | semmle.label | (size_t)... |
#select
| test.cpp:42:31:42:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
| test.cpp:43:31:43:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:63 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
@@ -149,3 +245,10 @@ nodes
| test.cpp:134:10:134:27 | ... * ... | test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:13 | size | This allocation size is derived from $@ and might overflow | test.cpp:132:19:132:24 | call to getenv | user input (getenv) |
| test.cpp:142:4:142:9 | call to malloc | test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:28 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:138:19:138:24 | call to getenv | user input (getenv) |
| test.cpp:142:11:142:28 | ... * ... | test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:14 | size | This allocation size is derived from $@ and might overflow | test.cpp:138:19:138:24 | call to getenv | user input (getenv) |
+| test.cpp:201:9:201:42 | ... * ... | test.cpp:201:14:201:19 | call to getenv | test.cpp:201:9:201:12 | call to atoi | This allocation size is derived from $@ and might overflow | test.cpp:201:14:201:19 | call to getenv | user input (getenv) |
+| test.cpp:206:13:206:46 | ... * ... | test.cpp:206:18:206:23 | call to getenv | test.cpp:206:13:206:16 | call to atoi | This allocation size is derived from $@ and might overflow | test.cpp:206:18:206:23 | call to getenv | user input (getenv) |
+| test.cpp:215:14:215:19 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:215:21:215:21 | s | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (getenv) |
+| test.cpp:221:14:221:19 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:221:21:221:21 | s | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (getenv) |
+| test.cpp:227:19:227:52 | ... * ... | test.cpp:227:24:227:29 | call to getenv | test.cpp:227:19:227:22 | call to atoi | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (getenv) |
+| test.cpp:229:2:229:7 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | local_size | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (getenv) |
+| test.cpp:231:2:231:7 | call to malloc | test.cpp:201:14:201:19 | call to getenv | test.cpp:231:9:231:24 | call to get_tainted_size | This allocation size is derived from $@ and might overflow | test.cpp:201:14:201:19 | call to getenv | user input (getenv) |
diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp
index 4a1bbd8a9dc..cb21e8f1915 100644
--- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp
+++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp
@@ -5,8 +5,8 @@ typedef struct {} FILE;
void *malloc(size_t size);
void *realloc(void *ptr, size_t size);
+void free(void *ptr);
int atoi(const char *nptr);
-
struct MyStruct
{
char data[256];
@@ -190,3 +190,49 @@ void more_bounded_tests() {
}
}
}
+
+size_t get_untainted_size()
+{
+ return 10 * sizeof(int);
+}
+
+size_t get_tainted_size()
+{
+ return atoi(getenv("USER")) * sizeof(int);
+}
+
+size_t get_bounded_size()
+{
+ size_t s = atoi(getenv("USER")) * sizeof(int);
+
+ if (s < 0) { s = 0; }
+ if (s > 100) { s = 100; }
+
+ return s;
+}
+
+void *my_alloc(size_t s) {
+ void *ptr = malloc(s); // [UNHELPFUL RESULT]
+
+ return ptr;
+}
+
+void my_func(size_t s) {
+ void *ptr = malloc(s); // BAD
+
+ free(ptr);
+}
+
+void more_cases() {
+ int local_size = atoi(getenv("USER")) * sizeof(int);
+
+ malloc(local_size); // BAD
+ malloc(get_untainted_size()); // GOOD
+ malloc(get_tainted_size()); // BAD
+ malloc(get_bounded_size()); // GOOD
+
+ my_alloc(100); // GOOD
+ my_alloc(local_size); // BAD [NOT DETECTED IN CORRECT LOCATION]
+ my_func(100); // GOOD
+ my_func(local_size); // GOOD
+}
From a7979fdc12405d22aa1d965a7bc6ed82669b4ec4 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 9 Apr 2020 11:29:52 +0100
Subject: [PATCH 0102/1298] C++: Base results purely on allocations now, not
multiplications by a sizeof.
---
.../CWE/CWE-190/TaintedAllocationSize.ql | 6 +-
.../TaintedAllocationSize.expected | 116 ------------------
2 files changed, 1 insertion(+), 121 deletions(-)
diff --git a/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql b/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql
index 2ed95e6cb55..a4f85ea4a8f 100644
--- a/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql
+++ b/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql
@@ -16,11 +16,7 @@ import semmle.code.cpp.security.TaintTracking
import TaintedWithPath
predicate taintedChild(Expr e, Expr tainted) {
- (
- isAllocationExpr(e)
- or
- any(MulExpr me | me.getAChild() instanceof SizeofOperator) = e
- ) and
+ isAllocationExpr(e) and
tainted = e.getAChild() and
tainted.getUnspecifiedType() instanceof IntegralType
}
diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected
index 4aa02918186..773a969e9ad 100644
--- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected
+++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected
@@ -5,12 +5,6 @@ edges
| test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted |
| test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted |
| test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted |
-| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:44 | (unsigned long)... |
-| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:44 | (unsigned long)... |
-| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:44 | tainted |
-| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:44 | tainted |
-| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:44 | tainted |
-| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:44 | tainted |
| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:63 | ... * ... |
| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:63 | ... * ... |
| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:63 | ... * ... |
@@ -33,91 +27,31 @@ edges
| test.cpp:39:21:39:24 | argv | test.cpp:52:35:52:60 | ... * ... |
| test.cpp:39:21:39:24 | argv | test.cpp:52:35:52:60 | ... * ... |
| test.cpp:39:21:39:24 | argv | test.cpp:52:35:52:60 | ... * ... |
-| test.cpp:39:21:39:24 | argv | test.cpp:52:54:52:60 | (unsigned long)... |
-| test.cpp:39:21:39:24 | argv | test.cpp:52:54:52:60 | (unsigned long)... |
-| test.cpp:39:21:39:24 | argv | test.cpp:52:54:52:60 | tainted |
-| test.cpp:39:21:39:24 | argv | test.cpp:52:54:52:60 | tainted |
-| test.cpp:39:21:39:24 | argv | test.cpp:52:54:52:60 | tainted |
-| test.cpp:39:21:39:24 | argv | test.cpp:52:54:52:60 | tainted |
-| test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:27 | (unsigned long)... |
-| test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:27 | size |
-| test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:27 | size |
| test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:41 | ... * ... |
| test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:41 | ... * ... |
-| test.cpp:123:18:123:31 | (const char *)... | test.cpp:127:24:127:27 | (unsigned long)... |
-| test.cpp:123:18:123:31 | (const char *)... | test.cpp:127:24:127:27 | size |
-| test.cpp:123:18:123:31 | (const char *)... | test.cpp:127:24:127:27 | size |
| test.cpp:123:18:123:31 | (const char *)... | test.cpp:127:24:127:41 | ... * ... |
| test.cpp:123:18:123:31 | (const char *)... | test.cpp:127:24:127:41 | ... * ... |
-| test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:13 | (unsigned long)... |
-| test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:13 | size |
-| test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:13 | size |
| test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:27 | ... * ... |
| test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:27 | ... * ... |
-| test.cpp:132:19:132:32 | (const char *)... | test.cpp:134:10:134:13 | (unsigned long)... |
-| test.cpp:132:19:132:32 | (const char *)... | test.cpp:134:10:134:13 | size |
-| test.cpp:132:19:132:32 | (const char *)... | test.cpp:134:10:134:13 | size |
| test.cpp:132:19:132:32 | (const char *)... | test.cpp:134:10:134:27 | ... * ... |
| test.cpp:132:19:132:32 | (const char *)... | test.cpp:134:10:134:27 | ... * ... |
-| test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:14 | (unsigned long)... |
-| test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:14 | size |
-| test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:14 | size |
| test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:28 | ... * ... |
| test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:28 | ... * ... |
-| test.cpp:138:19:138:32 | (const char *)... | test.cpp:142:11:142:14 | (unsigned long)... |
-| test.cpp:138:19:138:32 | (const char *)... | test.cpp:142:11:142:14 | size |
-| test.cpp:138:19:138:32 | (const char *)... | test.cpp:142:11:142:14 | size |
| test.cpp:138:19:138:32 | (const char *)... | test.cpp:142:11:142:28 | ... * ... |
| test.cpp:138:19:138:32 | (const char *)... | test.cpp:142:11:142:28 | ... * ... |
-| test.cpp:201:9:201:12 | call to atoi | test.cpp:201:9:201:12 | call to atoi |
-| test.cpp:201:9:201:12 | call to atoi | test.cpp:201:9:201:28 | (unsigned long)... |
-| test.cpp:201:9:201:12 | call to atoi | test.cpp:201:9:201:42 | Store |
| test.cpp:201:9:201:42 | Store | test.cpp:231:9:231:24 | call to get_tainted_size |
| test.cpp:201:9:201:42 | Store | test.cpp:231:9:231:24 | call to get_tainted_size |
-| test.cpp:201:14:201:19 | call to getenv | test.cpp:201:9:201:12 | call to atoi |
-| test.cpp:201:14:201:19 | call to getenv | test.cpp:201:9:201:12 | call to atoi |
-| test.cpp:201:14:201:19 | call to getenv | test.cpp:201:9:201:12 | call to atoi |
-| test.cpp:201:14:201:19 | call to getenv | test.cpp:201:9:201:28 | (unsigned long)... |
| test.cpp:201:14:201:19 | call to getenv | test.cpp:201:9:201:42 | Store |
-| test.cpp:201:14:201:27 | (const char *)... | test.cpp:201:9:201:12 | call to atoi |
-| test.cpp:201:14:201:27 | (const char *)... | test.cpp:201:9:201:12 | call to atoi |
-| test.cpp:201:14:201:27 | (const char *)... | test.cpp:201:9:201:12 | call to atoi |
-| test.cpp:201:14:201:27 | (const char *)... | test.cpp:201:9:201:28 | (unsigned long)... |
| test.cpp:201:14:201:27 | (const char *)... | test.cpp:201:9:201:42 | Store |
-| test.cpp:206:13:206:16 | call to atoi | test.cpp:206:13:206:16 | call to atoi |
-| test.cpp:206:13:206:16 | call to atoi | test.cpp:206:13:206:32 | (unsigned long)... |
-| test.cpp:206:18:206:23 | call to getenv | test.cpp:206:13:206:16 | call to atoi |
-| test.cpp:206:18:206:23 | call to getenv | test.cpp:206:13:206:16 | call to atoi |
-| test.cpp:206:18:206:23 | call to getenv | test.cpp:206:13:206:16 | call to atoi |
-| test.cpp:206:18:206:23 | call to getenv | test.cpp:206:13:206:32 | (unsigned long)... |
-| test.cpp:206:18:206:31 | (const char *)... | test.cpp:206:13:206:16 | call to atoi |
-| test.cpp:206:18:206:31 | (const char *)... | test.cpp:206:13:206:16 | call to atoi |
-| test.cpp:206:18:206:31 | (const char *)... | test.cpp:206:13:206:16 | call to atoi |
-| test.cpp:206:18:206:31 | (const char *)... | test.cpp:206:13:206:32 | (unsigned long)... |
| test.cpp:214:23:214:23 | s | test.cpp:215:21:215:21 | s |
| test.cpp:214:23:214:23 | s | test.cpp:215:21:215:21 | s |
| test.cpp:220:21:220:21 | s | test.cpp:221:21:221:21 | s |
| test.cpp:220:21:220:21 | s | test.cpp:221:21:221:21 | s |
-| test.cpp:227:19:227:22 | call to atoi | test.cpp:227:19:227:22 | call to atoi |
-| test.cpp:227:19:227:22 | call to atoi | test.cpp:227:19:227:38 | (unsigned long)... |
-| test.cpp:227:19:227:22 | call to atoi | test.cpp:229:9:229:18 | (size_t)... |
-| test.cpp:227:19:227:22 | call to atoi | test.cpp:229:9:229:18 | local_size |
-| test.cpp:227:19:227:22 | call to atoi | test.cpp:229:9:229:18 | local_size |
-| test.cpp:227:19:227:22 | call to atoi | test.cpp:235:11:235:20 | (size_t)... |
-| test.cpp:227:19:227:22 | call to atoi | test.cpp:237:10:237:19 | (size_t)... |
-| test.cpp:227:24:227:29 | call to getenv | test.cpp:227:19:227:22 | call to atoi |
-| test.cpp:227:24:227:29 | call to getenv | test.cpp:227:19:227:22 | call to atoi |
-| test.cpp:227:24:227:29 | call to getenv | test.cpp:227:19:227:22 | call to atoi |
-| test.cpp:227:24:227:29 | call to getenv | test.cpp:227:19:227:38 | (unsigned long)... |
| test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | (size_t)... |
| test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | local_size |
| test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | local_size |
| test.cpp:227:24:227:29 | call to getenv | test.cpp:235:11:235:20 | (size_t)... |
| test.cpp:227:24:227:29 | call to getenv | test.cpp:237:10:237:19 | (size_t)... |
-| test.cpp:227:24:227:37 | (const char *)... | test.cpp:227:19:227:22 | call to atoi |
-| test.cpp:227:24:227:37 | (const char *)... | test.cpp:227:19:227:22 | call to atoi |
-| test.cpp:227:24:227:37 | (const char *)... | test.cpp:227:19:227:22 | call to atoi |
-| test.cpp:227:24:227:37 | (const char *)... | test.cpp:227:19:227:38 | (unsigned long)... |
| test.cpp:227:24:227:37 | (const char *)... | test.cpp:229:9:229:18 | (size_t)... |
| test.cpp:227:24:227:37 | (const char *)... | test.cpp:229:9:229:18 | local_size |
| test.cpp:227:24:227:37 | (const char *)... | test.cpp:229:9:229:18 | local_size |
@@ -133,11 +67,6 @@ nodes
| test.cpp:42:38:42:44 | tainted | semmle.label | tainted |
| test.cpp:42:38:42:44 | tainted | semmle.label | tainted |
| test.cpp:42:38:42:44 | tainted | semmle.label | tainted |
-| test.cpp:43:38:43:44 | (unsigned long)... | semmle.label | (unsigned long)... |
-| test.cpp:43:38:43:44 | (unsigned long)... | semmle.label | (unsigned long)... |
-| test.cpp:43:38:43:44 | tainted | semmle.label | tainted |
-| test.cpp:43:38:43:44 | tainted | semmle.label | tainted |
-| test.cpp:43:38:43:44 | tainted | semmle.label | tainted |
| test.cpp:43:38:43:63 | ... * ... | semmle.label | ... * ... |
| test.cpp:43:38:43:63 | ... * ... | semmle.label | ... * ... |
| test.cpp:43:38:43:63 | ... * ... | semmle.label | ... * ... |
@@ -155,56 +84,24 @@ nodes
| test.cpp:52:35:52:60 | ... * ... | semmle.label | ... * ... |
| test.cpp:52:35:52:60 | ... * ... | semmle.label | ... * ... |
| test.cpp:52:35:52:60 | ... * ... | semmle.label | ... * ... |
-| test.cpp:52:54:52:60 | (unsigned long)... | semmle.label | (unsigned long)... |
-| test.cpp:52:54:52:60 | (unsigned long)... | semmle.label | (unsigned long)... |
-| test.cpp:52:54:52:60 | tainted | semmle.label | tainted |
-| test.cpp:52:54:52:60 | tainted | semmle.label | tainted |
-| test.cpp:52:54:52:60 | tainted | semmle.label | tainted |
| test.cpp:123:18:123:23 | call to getenv | semmle.label | call to getenv |
| test.cpp:123:18:123:31 | (const char *)... | semmle.label | (const char *)... |
-| test.cpp:127:24:127:27 | (unsigned long)... | semmle.label | (unsigned long)... |
-| test.cpp:127:24:127:27 | (unsigned long)... | semmle.label | (unsigned long)... |
-| test.cpp:127:24:127:27 | size | semmle.label | size |
-| test.cpp:127:24:127:27 | size | semmle.label | size |
-| test.cpp:127:24:127:27 | size | semmle.label | size |
| test.cpp:127:24:127:41 | ... * ... | semmle.label | ... * ... |
| test.cpp:127:24:127:41 | ... * ... | semmle.label | ... * ... |
| test.cpp:127:24:127:41 | ... * ... | semmle.label | ... * ... |
| test.cpp:132:19:132:24 | call to getenv | semmle.label | call to getenv |
| test.cpp:132:19:132:32 | (const char *)... | semmle.label | (const char *)... |
-| test.cpp:134:10:134:13 | (unsigned long)... | semmle.label | (unsigned long)... |
-| test.cpp:134:10:134:13 | (unsigned long)... | semmle.label | (unsigned long)... |
-| test.cpp:134:10:134:13 | size | semmle.label | size |
-| test.cpp:134:10:134:13 | size | semmle.label | size |
-| test.cpp:134:10:134:13 | size | semmle.label | size |
| test.cpp:134:10:134:27 | ... * ... | semmle.label | ... * ... |
| test.cpp:134:10:134:27 | ... * ... | semmle.label | ... * ... |
| test.cpp:134:10:134:27 | ... * ... | semmle.label | ... * ... |
| test.cpp:138:19:138:24 | call to getenv | semmle.label | call to getenv |
| test.cpp:138:19:138:32 | (const char *)... | semmle.label | (const char *)... |
-| test.cpp:142:11:142:14 | (unsigned long)... | semmle.label | (unsigned long)... |
-| test.cpp:142:11:142:14 | (unsigned long)... | semmle.label | (unsigned long)... |
-| test.cpp:142:11:142:14 | size | semmle.label | size |
-| test.cpp:142:11:142:14 | size | semmle.label | size |
-| test.cpp:142:11:142:14 | size | semmle.label | size |
| test.cpp:142:11:142:28 | ... * ... | semmle.label | ... * ... |
| test.cpp:142:11:142:28 | ... * ... | semmle.label | ... * ... |
| test.cpp:142:11:142:28 | ... * ... | semmle.label | ... * ... |
-| test.cpp:201:9:201:12 | call to atoi | semmle.label | call to atoi |
-| test.cpp:201:9:201:12 | call to atoi | semmle.label | call to atoi |
-| test.cpp:201:9:201:12 | call to atoi | semmle.label | call to atoi |
-| test.cpp:201:9:201:28 | (unsigned long)... | semmle.label | (unsigned long)... |
-| test.cpp:201:9:201:28 | (unsigned long)... | semmle.label | (unsigned long)... |
| test.cpp:201:9:201:42 | Store | semmle.label | Store |
| test.cpp:201:14:201:19 | call to getenv | semmle.label | call to getenv |
| test.cpp:201:14:201:27 | (const char *)... | semmle.label | (const char *)... |
-| test.cpp:206:13:206:16 | call to atoi | semmle.label | call to atoi |
-| test.cpp:206:13:206:16 | call to atoi | semmle.label | call to atoi |
-| test.cpp:206:13:206:16 | call to atoi | semmle.label | call to atoi |
-| test.cpp:206:13:206:32 | (unsigned long)... | semmle.label | (unsigned long)... |
-| test.cpp:206:13:206:32 | (unsigned long)... | semmle.label | (unsigned long)... |
-| test.cpp:206:18:206:23 | call to getenv | semmle.label | call to getenv |
-| test.cpp:206:18:206:31 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:214:23:214:23 | s | semmle.label | s |
| test.cpp:215:21:215:21 | s | semmle.label | s |
| test.cpp:215:21:215:21 | s | semmle.label | s |
@@ -213,11 +110,6 @@ nodes
| test.cpp:221:21:221:21 | s | semmle.label | s |
| test.cpp:221:21:221:21 | s | semmle.label | s |
| test.cpp:221:21:221:21 | s | semmle.label | s |
-| test.cpp:227:19:227:22 | call to atoi | semmle.label | call to atoi |
-| test.cpp:227:19:227:22 | call to atoi | semmle.label | call to atoi |
-| test.cpp:227:19:227:22 | call to atoi | semmle.label | call to atoi |
-| test.cpp:227:19:227:38 | (unsigned long)... | semmle.label | (unsigned long)... |
-| test.cpp:227:19:227:38 | (unsigned long)... | semmle.label | (unsigned long)... |
| test.cpp:227:24:227:29 | call to getenv | semmle.label | call to getenv |
| test.cpp:227:24:227:37 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:229:9:229:18 | (size_t)... | semmle.label | (size_t)... |
@@ -233,22 +125,14 @@ nodes
#select
| test.cpp:42:31:42:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
| test.cpp:43:31:43:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:63 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
-| test.cpp:43:38:43:63 | ... * ... | test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:44 | tainted | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
| test.cpp:45:31:45:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:45:38:45:63 | ... + ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
| test.cpp:48:25:48:30 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:48:32:48:35 | size | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
| test.cpp:49:17:49:30 | new[] | test.cpp:39:21:39:24 | argv | test.cpp:49:26:49:29 | size | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
| test.cpp:52:21:52:27 | call to realloc | test.cpp:39:21:39:24 | argv | test.cpp:52:35:52:60 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
-| test.cpp:52:35:52:60 | ... * ... | test.cpp:39:21:39:24 | argv | test.cpp:52:54:52:60 | tainted | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
| test.cpp:127:17:127:22 | call to malloc | test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:41 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:123:18:123:23 | call to getenv | user input (getenv) |
-| test.cpp:127:24:127:41 | ... * ... | test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:27 | size | This allocation size is derived from $@ and might overflow | test.cpp:123:18:123:23 | call to getenv | user input (getenv) |
| test.cpp:134:3:134:8 | call to malloc | test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:132:19:132:24 | call to getenv | user input (getenv) |
-| test.cpp:134:10:134:27 | ... * ... | test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:13 | size | This allocation size is derived from $@ and might overflow | test.cpp:132:19:132:24 | call to getenv | user input (getenv) |
| test.cpp:142:4:142:9 | call to malloc | test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:28 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:138:19:138:24 | call to getenv | user input (getenv) |
-| test.cpp:142:11:142:28 | ... * ... | test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:14 | size | This allocation size is derived from $@ and might overflow | test.cpp:138:19:138:24 | call to getenv | user input (getenv) |
-| test.cpp:201:9:201:42 | ... * ... | test.cpp:201:14:201:19 | call to getenv | test.cpp:201:9:201:12 | call to atoi | This allocation size is derived from $@ and might overflow | test.cpp:201:14:201:19 | call to getenv | user input (getenv) |
-| test.cpp:206:13:206:46 | ... * ... | test.cpp:206:18:206:23 | call to getenv | test.cpp:206:13:206:16 | call to atoi | This allocation size is derived from $@ and might overflow | test.cpp:206:18:206:23 | call to getenv | user input (getenv) |
| test.cpp:215:14:215:19 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:215:21:215:21 | s | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (getenv) |
| test.cpp:221:14:221:19 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:221:21:221:21 | s | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (getenv) |
-| test.cpp:227:19:227:52 | ... * ... | test.cpp:227:24:227:29 | call to getenv | test.cpp:227:19:227:22 | call to atoi | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (getenv) |
| test.cpp:229:2:229:7 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | local_size | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (getenv) |
| test.cpp:231:2:231:7 | call to malloc | test.cpp:201:14:201:19 | call to getenv | test.cpp:231:9:231:24 | call to get_tainted_size | This allocation size is derived from $@ and might overflow | test.cpp:201:14:201:19 | call to getenv | user input (getenv) |
From ba3a8d0872461e7106152ab377b52a3413a274cf Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 9 Apr 2020 13:10:22 +0100
Subject: [PATCH 0103/1298] C++: Improve naming and QLDoc.
---
.../CWE/CWE-190/TaintedAllocationSize.ql | 22 +++++++++++--------
1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql b/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql
index a4f85ea4a8f..54c6d1e7a96 100644
--- a/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql
+++ b/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql
@@ -15,27 +15,31 @@ import cpp
import semmle.code.cpp.security.TaintTracking
import TaintedWithPath
-predicate taintedChild(Expr e, Expr tainted) {
- isAllocationExpr(e) and
- tainted = e.getAChild() and
+/**
+ * Holds if `alloc` is an allocation, and `tainted` is a child of it that is a
+ * taint sink.
+ */
+predicate allocSink(Expr alloc, Expr tainted) {
+ isAllocationExpr(alloc) and
+ tainted = alloc.getAChild() and
tainted.getUnspecifiedType() instanceof IntegralType
}
class TaintedAllocationSizeConfiguration extends TaintTrackingConfiguration {
- override predicate isSink(Element tainted) { taintedChild(_, tainted) }
+ override predicate isSink(Element tainted) { allocSink(_, tainted) }
}
predicate taintedAllocSize(
- Expr e, Expr source, PathNode sourceNode, PathNode sinkNode, string taintCause
+ Expr source, Expr alloc, PathNode sourceNode, PathNode sinkNode, string taintCause
) {
isUserInput(source, taintCause) and
exists(Expr tainted |
- taintedChild(e, tainted) and
+ allocSink(alloc, tainted) and
taintedWithPath(source, tainted, sourceNode, sinkNode)
)
}
-from Expr e, Expr source, PathNode sourceNode, PathNode sinkNode, string taintCause
-where taintedAllocSize(e, source, sourceNode, sinkNode, taintCause)
-select e, sourceNode, sinkNode, "This allocation size is derived from $@ and might overflow",
+from Expr source, Expr alloc, PathNode sourceNode, PathNode sinkNode, string taintCause
+where taintedAllocSize(source, alloc, sourceNode, sinkNode, taintCause)
+select alloc, sourceNode, sinkNode, "This allocation size is derived from $@ and might overflow",
source, "user input (" + taintCause + ")"
From 7a586c97a46e64a307af8eb872d7f542c0f3a89a Mon Sep 17 00:00:00 2001
From: Rebecca Valentine
Date: Thu, 9 Apr 2020 14:30:40 -0700
Subject: [PATCH 0104/1298] Python: ObjectAPI to ValueAPI:
IterReturnsNonIterature: Replaces custom return_type predicate with call to
getAnInferredReturnType
---
python/ql/src/Functions/IterReturnsNonIterator.ql | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/python/ql/src/Functions/IterReturnsNonIterator.ql b/python/ql/src/Functions/IterReturnsNonIterator.ql
index 20e3d311fa8..405bff78c04 100644
--- a/python/ql/src/Functions/IterReturnsNonIterator.ql
+++ b/python/ql/src/Functions/IterReturnsNonIterator.ql
@@ -12,18 +12,10 @@
import python
-ClassValue return_type(FunctionValue f) {
- exists(ControlFlowNode n, Return ret |
- ret.getScope() = f.getScope() and
- ret.getValue() = n.getNode() and
- result = n.pointsTo().getClass()
- )
-}
-
from ClassValue iterable, FunctionValue iter, ClassValue iterator
where
iter = iterable.lookup("__iter__") and
- iterator = return_type(iter) and
+ iterator = iter.getAnInferredReturnType() and
not iterator.isIterator()
select iterator,
"Class " + iterator.getName() +
From be00d71b99ab8346895841a50f0cd07c774f6347 Mon Sep 17 00:00:00 2001
From: Rebecca Valentine
Date: Thu, 9 Apr 2020 14:41:22 -0700
Subject: [PATCH 0105/1298] Python: ObjectAPI to ValueAPI:
IncorrectlyOverriddenMethod: Adds preliminary modernization
---
.../src/Functions/IncorrectlyOverriddenMethod.ql | 10 +++++-----
.../ql/src/semmle/python/objects/ObjectAPI.qll | 16 ++++++++++++++++
.../IncorrectlyOverriddenMethod.expected | 12 ++++++------
3 files changed, 27 insertions(+), 11 deletions(-)
diff --git a/python/ql/src/Functions/IncorrectlyOverriddenMethod.ql b/python/ql/src/Functions/IncorrectlyOverriddenMethod.ql
index 53d70815ddd..953641a6c6a 100644
--- a/python/ql/src/Functions/IncorrectlyOverriddenMethod.ql
+++ b/python/ql/src/Functions/IncorrectlyOverriddenMethod.ql
@@ -12,17 +12,17 @@
import python
import Expressions.CallArgs
-from Call call, FunctionObject func, FunctionObject overridden, string problem
+from Call call, FunctionValue func, FunctionValue overridden, string problem
where
func.overrides(overridden) and
(
- wrong_args_objectapi(call, func, _, problem) and
- correct_args_if_called_as_method_objectapi(call, overridden)
+ wrong_args(call, func, _, problem) and
+ correct_args_if_called_as_method(call, overridden)
or
exists(string name |
- illegally_named_parameter_objectapi(call, func, name) and
+ illegally_named_parameter(call, func, name) and
problem = "an argument named '" + name + "'" and
- overridden.getFunction().getAnArg().(Name).getId() = name
+ overridden.getScope().getAnArg().(Name).getId() = name
)
)
select func,
diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll
index 9772a77ed8b..48367ec1a7c 100644
--- a/python/ql/src/semmle/python/objects/ObjectAPI.qll
+++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll
@@ -573,6 +573,9 @@ class ClassValue extends Value {
abstract class FunctionValue extends CallableValue {
abstract string getQualifiedName();
+ /** Gets a longer, more descriptive version of toString() */
+ abstract string descriptiveString();
+
/** Gets the minimum number of parameters that can be correctly passed to this function */
abstract int minParameters();
@@ -617,6 +620,15 @@ class PythonFunctionValue extends FunctionValue {
result = this.(PythonFunctionObjectInternal).getScope().getQualifiedName()
}
+ override string descriptiveString() {
+ if this.getScope().isMethod()
+ then
+ exists(Class cls | this.getScope().getScope() = cls |
+ result = "method " + this.getQualifiedName()
+ )
+ else result = "function " + this.getQualifiedName()
+ }
+
override int minParameters() {
exists(Function f |
f = this.getScope() and
@@ -650,6 +662,8 @@ class BuiltinFunctionValue extends FunctionValue {
override string getQualifiedName() { result = this.(BuiltinFunctionObjectInternal).getName() }
+ override string descriptiveString() { result = "builtin-function " + this.getName() }
+
override int minParameters() { none() }
override int maxParameters() { none() }
@@ -674,6 +688,8 @@ class BuiltinMethodValue extends FunctionValue {
)
}
+ override string descriptiveString() { result = "builtin-method " + this.getQualifiedName() }
+
override int minParameters() { none() }
override int maxParameters() { none() }
diff --git a/python/ql/test/query-tests/Functions/overriding/IncorrectlyOverriddenMethod.expected b/python/ql/test/query-tests/Functions/overriding/IncorrectlyOverriddenMethod.expected
index 92276ba22f0..61b9eff9d67 100644
--- a/python/ql/test/query-tests/Functions/overriding/IncorrectlyOverriddenMethod.expected
+++ b/python/ql/test/query-tests/Functions/overriding/IncorrectlyOverriddenMethod.expected
@@ -1,6 +1,6 @@
-| test.py:24:5:24:26 | Function meth1 | Overriding method signature does not match $@, where it is passed too few. Overridden method $@ is correctly specified. | test.py:15:9:15:20 | Attribute() | here | test.py:5:5:5:20 | Function meth1 | method Base.meth1 |
-| test.py:24:5:24:26 | Function meth1 | Overriding method signature does not match $@, where it is passed too few. Overridden method $@ is correctly specified. | test.py:34:9:34:20 | Attribute() | here | test.py:5:5:5:20 | Function meth1 | method Base.meth1 |
-| test.py:27:5:27:20 | Function meth2 | Overriding method signature does not match $@, where it is passed an argument named 'spam'. Overridden method $@ is correctly specified. | test.py:20:9:20:31 | Attribute() | here | test.py:8:5:8:26 | Function meth2 | method Base.meth2 |
-| test.py:27:5:27:20 | Function meth2 | Overriding method signature does not match $@, where it is passed an argument named 'spam'. Overridden method $@ is correctly specified. | test.py:39:9:39:31 | Attribute() | here | test.py:8:5:8:26 | Function meth2 | method Base.meth2 |
-| test.py:27:5:27:20 | Function meth2 | Overriding method signature does not match $@, where it is passed too many. Overridden method $@ is correctly specified. | test.py:18:9:18:21 | Attribute() | here | test.py:8:5:8:26 | Function meth2 | method Base.meth2 |
-| test.py:27:5:27:20 | Function meth2 | Overriding method signature does not match $@, where it is passed too many. Overridden method $@ is correctly specified. | test.py:37:9:37:21 | Attribute() | here | test.py:8:5:8:26 | Function meth2 | method Base.meth2 |
+| test.py:24:5:24:26 | Function Derived.meth1 | Overriding method signature does not match $@, where it is passed too few. Overridden method $@ is correctly specified. | test.py:15:9:15:20 | Attribute() | here | test.py:5:5:5:20 | Function Base.meth1 | method Base.meth1 |
+| test.py:24:5:24:26 | Function Derived.meth1 | Overriding method signature does not match $@, where it is passed too few. Overridden method $@ is correctly specified. | test.py:34:9:34:20 | Attribute() | here | test.py:5:5:5:20 | Function Base.meth1 | method Base.meth1 |
+| test.py:27:5:27:20 | Function Derived.meth2 | Overriding method signature does not match $@, where it is passed an argument named 'spam'. Overridden method $@ is correctly specified. | test.py:20:9:20:31 | Attribute() | here | test.py:8:5:8:26 | Function Base.meth2 | method Base.meth2 |
+| test.py:27:5:27:20 | Function Derived.meth2 | Overriding method signature does not match $@, where it is passed an argument named 'spam'. Overridden method $@ is correctly specified. | test.py:39:9:39:31 | Attribute() | here | test.py:8:5:8:26 | Function Base.meth2 | method Base.meth2 |
+| test.py:27:5:27:20 | Function Derived.meth2 | Overriding method signature does not match $@, where it is passed too many. Overridden method $@ is correctly specified. | test.py:18:9:18:21 | Attribute() | here | test.py:8:5:8:26 | Function Base.meth2 | method Base.meth2 |
+| test.py:27:5:27:20 | Function Derived.meth2 | Overriding method signature does not match $@, where it is passed too many. Overridden method $@ is correctly specified. | test.py:37:9:37:21 | Attribute() | here | test.py:8:5:8:26 | Function Base.meth2 | method Base.meth2 |
From 336e48c5c64f78dcf662854e6c3eb1758d349d3d Mon Sep 17 00:00:00 2001
From: Rebecca Valentine
Date: Thu, 9 Apr 2020 14:50:26 -0700
Subject: [PATCH 0106/1298] Python: ObjectAPI to ValueAPI:
IncorrectlySpecifiedOverriddenMethod: Adds preliminary modernization
---
.../IncorrectlySpecifiedOverriddenMethod.ql | 12 +++++-----
.../src/semmle/python/objects/ObjectAPI.qll | 24 +++++++++++++++++++
...orrectlySpecifiedOverriddenMethod.expected | 18 +++++++-------
3 files changed, 39 insertions(+), 15 deletions(-)
diff --git a/python/ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql b/python/ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql
index 0dd0fd5856b..66ea5e43831 100644
--- a/python/ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql
+++ b/python/ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql
@@ -13,21 +13,21 @@
import python
import Expressions.CallArgs
-from Call call, FunctionObject func, FunctionObject overriding, string problem
+from Call call, FunctionValue func, FunctionValue overriding, string problem
where
not func.getName() = "__init__" and
overriding.overrides(func) and
call = overriding.getAMethodCall().getNode() and
- correct_args_if_called_as_method_objectapi(call, overriding) and
+ correct_args_if_called_as_method(call, overriding) and
(
- arg_count_objectapi(call) + 1 < func.minParameters() and problem = "too few arguments"
+ arg_count(call) + 1 < func.minParameters() and problem = "too few arguments"
or
- arg_count_objectapi(call) >= func.maxParameters() and problem = "too many arguments"
+ arg_count(call) >= func.maxParameters() and problem = "too many arguments"
or
exists(string name |
call.getAKeyword().getArg() = name and
- overriding.getFunction().getAnArg().(Name).getId() = name and
- not func.getFunction().getAnArg().(Name).getId() = name and
+ overriding.getScope().getAnArg().(Name).getId() = name and
+ not func.getScope().getAnArg().(Name).getId() = name and
problem = "an argument named '" + name + "'"
)
)
diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll
index 9772a77ed8b..0763bd1ba77 100644
--- a/python/ql/src/semmle/python/objects/ObjectAPI.qll
+++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll
@@ -573,6 +573,9 @@ class ClassValue extends Value {
abstract class FunctionValue extends CallableValue {
abstract string getQualifiedName();
+ /** Gets a longer, more descriptive version of toString() */
+ abstract string descriptiveString();
+
/** Gets the minimum number of parameters that can be correctly passed to this function */
abstract int minParameters();
@@ -605,6 +608,14 @@ abstract class FunctionValue extends CallableValue {
)
}
+ /** Gets a call-site from where this function is called as a method */
+ CallNode getAMethodCall() {
+ exists(BoundMethodObjectInternal bm |
+ result.getFunction().pointsTo() = bm and
+ bm.getFunction() = this
+ )
+ }
+
/** Gets a class that this function may return */
abstract ClassValue getAnInferredReturnType();
}
@@ -617,6 +628,15 @@ class PythonFunctionValue extends FunctionValue {
result = this.(PythonFunctionObjectInternal).getScope().getQualifiedName()
}
+ override string descriptiveString() {
+ if this.getScope().isMethod()
+ then
+ exists(Class cls | this.getScope().getScope() = cls |
+ result = "method " + this.getQualifiedName()
+ )
+ else result = "function " + this.getQualifiedName()
+ }
+
override int minParameters() {
exists(Function f |
f = this.getScope() and
@@ -650,6 +670,8 @@ class BuiltinFunctionValue extends FunctionValue {
override string getQualifiedName() { result = this.(BuiltinFunctionObjectInternal).getName() }
+ override string descriptiveString() { result = "builtin-function " + this.getName() }
+
override int minParameters() { none() }
override int maxParameters() { none() }
@@ -674,6 +696,8 @@ class BuiltinMethodValue extends FunctionValue {
)
}
+ override string descriptiveString() { result = "builtin-method " + this.getQualifiedName() }
+
override int minParameters() { none() }
override int maxParameters() { none() }
diff --git a/python/ql/test/query-tests/Functions/overriding/IncorrectlySpecifiedOverriddenMethod.expected b/python/ql/test/query-tests/Functions/overriding/IncorrectlySpecifiedOverriddenMethod.expected
index 527ad805604..3192999aad2 100644
--- a/python/ql/test/query-tests/Functions/overriding/IncorrectlySpecifiedOverriddenMethod.expected
+++ b/python/ql/test/query-tests/Functions/overriding/IncorrectlySpecifiedOverriddenMethod.expected
@@ -1,9 +1,9 @@
-| test.py:5:5:5:20 | Function meth1 | Overridden method signature does not match $@, where it is passed an argument named 'spam'. Overriding method $@ matches the call. | test.py:19:9:19:31 | Attribute() | call | test.py:24:5:24:26 | Function meth1 | method Derived.meth1 |
-| test.py:5:5:5:20 | Function meth1 | Overridden method signature does not match $@, where it is passed an argument named 'spam'. Overriding method $@ matches the call. | test.py:38:9:38:31 | Attribute() | call | test.py:24:5:24:26 | Function meth1 | method Derived.meth1 |
-| test.py:5:5:5:20 | Function meth1 | Overridden method signature does not match $@, where it is passed too many arguments. Overriding method $@ matches the call. | test.py:16:9:16:21 | Attribute() | call | test.py:24:5:24:26 | Function meth1 | method Derived.meth1 |
-| test.py:5:5:5:20 | Function meth1 | Overridden method signature does not match $@, where it is passed too many arguments. Overriding method $@ matches the call. | test.py:19:9:19:31 | Attribute() | call | test.py:24:5:24:26 | Function meth1 | method Derived.meth1 |
-| test.py:5:5:5:20 | Function meth1 | Overridden method signature does not match $@, where it is passed too many arguments. Overriding method $@ matches the call. | test.py:35:9:35:21 | Attribute() | call | test.py:24:5:24:26 | Function meth1 | method Derived.meth1 |
-| test.py:5:5:5:20 | Function meth1 | Overridden method signature does not match $@, where it is passed too many arguments. Overriding method $@ matches the call. | test.py:38:9:38:31 | Attribute() | call | test.py:24:5:24:26 | Function meth1 | method Derived.meth1 |
-| test.py:8:5:8:26 | Function meth2 | Overridden method signature does not match $@, where it is passed too few arguments. Overriding method $@ matches the call. | test.py:17:9:17:20 | Attribute() | call | test.py:27:5:27:20 | Function meth2 | method Derived.meth2 |
-| test.py:8:5:8:26 | Function meth2 | Overridden method signature does not match $@, where it is passed too few arguments. Overriding method $@ matches the call. | test.py:36:9:36:20 | Attribute() | call | test.py:27:5:27:20 | Function meth2 | method Derived.meth2 |
-| test.py:64:5:64:19 | Function meth | Overridden method signature does not match $@, where it is passed too many arguments. Overriding method $@ matches the call. | test.py:78:1:78:12 | Attribute() | call | test.py:74:5:74:24 | Function meth | method Correct2.meth |
+| test.py:5:5:5:20 | Function Base.meth1 | Overridden method signature does not match $@, where it is passed an argument named 'spam'. Overriding method $@ matches the call. | test.py:19:9:19:31 | Attribute() | call | test.py:24:5:24:26 | Function Derived.meth1 | method Derived.meth1 |
+| test.py:5:5:5:20 | Function Base.meth1 | Overridden method signature does not match $@, where it is passed an argument named 'spam'. Overriding method $@ matches the call. | test.py:38:9:38:31 | Attribute() | call | test.py:24:5:24:26 | Function Derived.meth1 | method Derived.meth1 |
+| test.py:5:5:5:20 | Function Base.meth1 | Overridden method signature does not match $@, where it is passed too many arguments. Overriding method $@ matches the call. | test.py:16:9:16:21 | Attribute() | call | test.py:24:5:24:26 | Function Derived.meth1 | method Derived.meth1 |
+| test.py:5:5:5:20 | Function Base.meth1 | Overridden method signature does not match $@, where it is passed too many arguments. Overriding method $@ matches the call. | test.py:19:9:19:31 | Attribute() | call | test.py:24:5:24:26 | Function Derived.meth1 | method Derived.meth1 |
+| test.py:5:5:5:20 | Function Base.meth1 | Overridden method signature does not match $@, where it is passed too many arguments. Overriding method $@ matches the call. | test.py:35:9:35:21 | Attribute() | call | test.py:24:5:24:26 | Function Derived.meth1 | method Derived.meth1 |
+| test.py:5:5:5:20 | Function Base.meth1 | Overridden method signature does not match $@, where it is passed too many arguments. Overriding method $@ matches the call. | test.py:38:9:38:31 | Attribute() | call | test.py:24:5:24:26 | Function Derived.meth1 | method Derived.meth1 |
+| test.py:8:5:8:26 | Function Base.meth2 | Overridden method signature does not match $@, where it is passed too few arguments. Overriding method $@ matches the call. | test.py:17:9:17:20 | Attribute() | call | test.py:27:5:27:20 | Function Derived.meth2 | method Derived.meth2 |
+| test.py:8:5:8:26 | Function Base.meth2 | Overridden method signature does not match $@, where it is passed too few arguments. Overriding method $@ matches the call. | test.py:36:9:36:20 | Attribute() | call | test.py:27:5:27:20 | Function Derived.meth2 | method Derived.meth2 |
+| test.py:64:5:64:19 | Function BlameBase.meth | Overridden method signature does not match $@, where it is passed too many arguments. Overriding method $@ matches the call. | test.py:78:1:78:12 | Attribute() | call | test.py:74:5:74:24 | Function Correct2.meth | method Correct2.meth |
From 8dc1933a021aea77210af672d8409cace5ac998d Mon Sep 17 00:00:00 2001
From: Rebecca Valentine
Date: Thu, 9 Apr 2020 14:58:30 -0700
Subject: [PATCH 0107/1298] Python: ObjectAPI to ValueAPI:
WrongNumberArgumentsInClassInstantiation: Adds preliminary modernization
---
...rongNumberArgumentsInClassInstantiation.ql | 8 ++---
...mberArgumentsInClassInstantiation.expected | 30 +++++++++----------
2 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql b/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql
index f04d2350855..c8763bd8aa7 100644
--- a/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql
+++ b/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql
@@ -15,17 +15,17 @@
import python
import Expressions.CallArgs
-from Call call, ClassObject cls, string too, string should, int limit, FunctionObject init
+from Call call, ClassValue cls, string too, string should, int limit, FunctionValue init
where
(
- too_many_args_objectapi(call, cls, limit) and
+ too_many_args(call, cls, limit) and
too = "too many arguments" and
should = "no more than "
or
- too_few_args_objectapi(call, cls, limit) and
+ too_few_args(call, cls, limit) and
too = "too few arguments" and
should = "no fewer than "
) and
- init = get_function_or_initializer_objectapi(cls)
+ init = get_function_or_initializer(cls)
select call, "Call to $@ with " + too + "; should be " + should + limit.toString() + ".", init,
init.getQualifiedName()
diff --git a/python/ql/test/query-tests/Classes/Arguments/WrongNumberArgumentsInClassInstantiation.expected b/python/ql/test/query-tests/Classes/Arguments/WrongNumberArgumentsInClassInstantiation.expected
index b0c156dc867..f0df1fe58c9 100644
--- a/python/ql/test/query-tests/Classes/Arguments/WrongNumberArgumentsInClassInstantiation.expected
+++ b/python/ql/test/query-tests/Classes/Arguments/WrongNumberArgumentsInClassInstantiation.expected
@@ -1,15 +1,15 @@
-| wrong_arguments.py:37:1:37:4 | F0() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:4:5:4:26 | Function __init__ | F0.__init__ |
-| wrong_arguments.py:38:1:38:4 | F1() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:8:5:8:36 | Function __init__ | F1.__init__ |
-| wrong_arguments.py:39:1:39:4 | F2() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:12:5:12:30 | Function __init__ | F2.__init__ |
-| wrong_arguments.py:40:1:40:4 | F3() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:16:5:16:40 | Function __init__ | F3.__init__ |
-| wrong_arguments.py:41:1:41:4 | F4() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:20:5:20:31 | Function __init__ | F4.__init__ |
-| wrong_arguments.py:42:1:42:4 | F5() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:24:5:24:42 | Function __init__ | F5.__init__ |
-| wrong_arguments.py:43:1:43:5 | F6() | Call to $@ with too few arguments; should be no fewer than 2. | wrong_arguments.py:28:5:28:30 | Function __init__ | F6.__init__ |
-| wrong_arguments.py:44:1:44:7 | F7() | Call to $@ with too few arguments; should be no fewer than 3. | wrong_arguments.py:32:5:32:33 | Function __init__ | F7.__init__ |
-| wrong_arguments.py:48:1:48:7 | F0() | Call to $@ with too many arguments; should be no more than 1. | wrong_arguments.py:4:5:4:26 | Function __init__ | F0.__init__ |
-| wrong_arguments.py:49:1:49:9 | F1() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:8:5:8:36 | Function __init__ | F1.__init__ |
-| wrong_arguments.py:50:1:50:9 | F5() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:24:5:24:42 | Function __init__ | F5.__init__ |
-| wrong_arguments.py:51:1:51:9 | F6() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:28:5:28:30 | Function __init__ | F6.__init__ |
-| wrong_arguments.py:52:1:52:11 | F6() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:28:5:28:30 | Function __init__ | F6.__init__ |
-| wrong_arguments.py:85:1:85:12 | F6() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:28:5:28:30 | Function __init__ | F6.__init__ |
-| wrong_arguments.py:86:1:86:7 | F6() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:28:5:28:30 | Function __init__ | F6.__init__ |
+| wrong_arguments.py:37:1:37:4 | F0() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:4:5:4:26 | Function F0.__init__ | F0.__init__ |
+| wrong_arguments.py:38:1:38:4 | F1() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:8:5:8:36 | Function F1.__init__ | F1.__init__ |
+| wrong_arguments.py:39:1:39:4 | F2() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:12:5:12:30 | Function F2.__init__ | F2.__init__ |
+| wrong_arguments.py:40:1:40:4 | F3() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:16:5:16:40 | Function F3.__init__ | F3.__init__ |
+| wrong_arguments.py:41:1:41:4 | F4() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:20:5:20:31 | Function F4.__init__ | F4.__init__ |
+| wrong_arguments.py:42:1:42:4 | F5() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:24:5:24:42 | Function F5.__init__ | F5.__init__ |
+| wrong_arguments.py:43:1:43:5 | F6() | Call to $@ with too few arguments; should be no fewer than 2. | wrong_arguments.py:28:5:28:30 | Function F6.__init__ | F6.__init__ |
+| wrong_arguments.py:44:1:44:7 | F7() | Call to $@ with too few arguments; should be no fewer than 3. | wrong_arguments.py:32:5:32:33 | Function F7.__init__ | F7.__init__ |
+| wrong_arguments.py:48:1:48:7 | F0() | Call to $@ with too many arguments; should be no more than 1. | wrong_arguments.py:4:5:4:26 | Function F0.__init__ | F0.__init__ |
+| wrong_arguments.py:49:1:49:9 | F1() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:8:5:8:36 | Function F1.__init__ | F1.__init__ |
+| wrong_arguments.py:50:1:50:9 | F5() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:24:5:24:42 | Function F5.__init__ | F5.__init__ |
+| wrong_arguments.py:51:1:51:9 | F6() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:28:5:28:30 | Function F6.__init__ | F6.__init__ |
+| wrong_arguments.py:52:1:52:11 | F6() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:28:5:28:30 | Function F6.__init__ | F6.__init__ |
+| wrong_arguments.py:85:1:85:12 | F6() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:28:5:28:30 | Function F6.__init__ | F6.__init__ |
+| wrong_arguments.py:86:1:86:7 | F6() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:28:5:28:30 | Function F6.__init__ | F6.__init__ |
From 339758fa70465859710d21f1cc5172e279f8d58e Mon Sep 17 00:00:00 2001
From: Rebecca Valentine
Date: Thu, 9 Apr 2020 15:04:44 -0700
Subject: [PATCH 0108/1298] Python: ObjectAPI to ValueAPI:
WrongNameForArgumentInClassInstantiation: Adds preliminary modernization
---
.../Classes/WrongNameForArgumentInClassInstantiation.ql | 6 +++---
.../WrongNameForArgumentInClassInstantiation.expected | 8 ++++----
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/python/ql/src/Classes/WrongNameForArgumentInClassInstantiation.ql b/python/ql/src/Classes/WrongNameForArgumentInClassInstantiation.ql
index 3ac4454a019..f3276ac61ef 100644
--- a/python/ql/src/Classes/WrongNameForArgumentInClassInstantiation.ql
+++ b/python/ql/src/Classes/WrongNameForArgumentInClassInstantiation.ql
@@ -16,9 +16,9 @@
import python
import Expressions.CallArgs
-from Call call, ClassObject cls, string name, FunctionObject init
+from Call call, ClassValue cls, string name, FunctionValue init
where
- illegally_named_parameter_objectapi(call, cls, name) and
- init = get_function_or_initializer_objectapi(cls)
+ illegally_named_parameter(call, cls, name) and
+ init = get_function_or_initializer(cls)
select call, "Keyword argument '" + name + "' is not a supported parameter name of $@.", init,
init.getQualifiedName()
diff --git a/python/ql/test/query-tests/Classes/Arguments/WrongNameForArgumentInClassInstantiation.expected b/python/ql/test/query-tests/Classes/Arguments/WrongNameForArgumentInClassInstantiation.expected
index cf89ddfc44f..4bdb1134776 100644
--- a/python/ql/test/query-tests/Classes/Arguments/WrongNameForArgumentInClassInstantiation.expected
+++ b/python/ql/test/query-tests/Classes/Arguments/WrongNameForArgumentInClassInstantiation.expected
@@ -1,4 +1,4 @@
-| wrong_arguments.py:65:1:65:7 | F0() | Keyword argument 'y' is not a supported parameter name of $@. | wrong_arguments.py:4:5:4:26 | Function __init__ | F0.__init__ |
-| wrong_arguments.py:66:1:66:7 | F1() | Keyword argument 'z' is not a supported parameter name of $@. | wrong_arguments.py:8:5:8:36 | Function __init__ | F1.__init__ |
-| wrong_arguments.py:67:1:67:12 | F2() | Keyword argument 'y' is not a supported parameter name of $@. | wrong_arguments.py:12:5:12:30 | Function __init__ | F2.__init__ |
-| wrong_arguments.py:92:1:92:27 | F6() | Keyword argument 'z' is not a supported parameter name of $@. | wrong_arguments.py:28:5:28:30 | Function __init__ | F6.__init__ |
+| wrong_arguments.py:65:1:65:7 | F0() | Keyword argument 'y' is not a supported parameter name of $@. | wrong_arguments.py:4:5:4:26 | Function F0.__init__ | F0.__init__ |
+| wrong_arguments.py:66:1:66:7 | F1() | Keyword argument 'z' is not a supported parameter name of $@. | wrong_arguments.py:8:5:8:36 | Function F1.__init__ | F1.__init__ |
+| wrong_arguments.py:67:1:67:12 | F2() | Keyword argument 'y' is not a supported parameter name of $@. | wrong_arguments.py:12:5:12:30 | Function F2.__init__ | F2.__init__ |
+| wrong_arguments.py:92:1:92:27 | F6() | Keyword argument 'z' is not a supported parameter name of $@. | wrong_arguments.py:28:5:28:30 | Function F6.__init__ | F6.__init__ |
From 8e91f100306d1e475bdc49ffb8ba4ffd1473faff Mon Sep 17 00:00:00 2001
From: Rebecca Valentine
Date: Thu, 9 Apr 2020 15:25:38 -0700
Subject: [PATCH 0109/1298] Python: ObjectAPI to ValueAPI: UselessClass: Adds
preliminary modernization
---
python/ql/src/Classes/UselessClass.ql | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/python/ql/src/Classes/UselessClass.ql b/python/ql/src/Classes/UselessClass.ql
index 2c872420049..e4e3f31f3a2 100644
--- a/python/ql/src/Classes/UselessClass.ql
+++ b/python/ql/src/Classes/UselessClass.ql
@@ -22,9 +22,9 @@ predicate does_not_define_special_method(Class cls) {
}
predicate no_inheritance(Class c) {
- not exists(ClassObject cls, ClassObject other |
- cls.getPyClass() = c and
- other != theObjectType()
+ not exists(ClassValue cls, ClassValue other |
+ cls.getScope() = c and
+ other != ClassValue::object()
|
other.getABaseType() = cls or
cls.getABaseType() = other
From 945ecffd05da4580abee5df56a65f399f86c50c4 Mon Sep 17 00:00:00 2001
From: Mathias Vorreiter Pedersen
Date: Mon, 13 Apr 2020 14:18:57 +0200
Subject: [PATCH 0110/1298] C++: Add charpred to ParameterNode
---
.../semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
index cec0ae1d138..cfe1196d5e9 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
@@ -162,6 +162,12 @@ class ExprNode extends InstructionNode {
* as `x` in `f(x)` and implicit parameters such as `this` in `x.f()`
*/
class ParameterNode extends InstructionNode {
+ ParameterNode() {
+ instr instanceof InitializeParameterInstruction
+ or
+ instr instanceof InitializeThisInstruction
+ }
+
/**
* Holds if this node is the parameter of `c` at the specified (zero-based)
* position. The implicit `this` parameter is considered to have index `-1`.
From cde34c9b1b284bb587eae31d151f04da15fbce5f Mon Sep 17 00:00:00 2001
From: Mathias Vorreiter Pedersen
Date: Mon, 13 Apr 2020 16:19:21 +0200
Subject: [PATCH 0111/1298] C++: Accept test output which I previously forgot
to accept
---
.../dataflow/fields/ir-flow.expected | 81 +++++++------------
.../literals/literals/literals.expected | 8 +-
.../CWE-134/semmle/funcs/funcsLocal.expected | 8 --
3 files changed, 34 insertions(+), 63 deletions(-)
diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
index 6d34e81e849..15a6d699adb 100644
--- a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
+++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
@@ -1,62 +1,41 @@
edges
-| aliasing.cpp:37:3:37:24 | Store : void | aliasing.cpp:38:11:38:12 | m1 |
-| aliasing.cpp:37:13:37:22 | call to user_input : void | aliasing.cpp:37:3:37:24 | Store : void |
-| aliasing.cpp:37:13:37:22 | call to user_input : void | aliasing.cpp:38:11:38:12 | m1 |
-| aliasing.cpp:42:3:42:22 | Store : void | aliasing.cpp:43:13:43:14 | m1 |
-| aliasing.cpp:42:11:42:20 | call to user_input : void | aliasing.cpp:42:3:42:22 | Store : void |
-| aliasing.cpp:42:11:42:20 | call to user_input : void | aliasing.cpp:43:13:43:14 | m1 |
-| aliasing.cpp:60:3:60:22 | Chi [m1] : void | aliasing.cpp:61:13:61:14 | Store [m1] : void |
-| aliasing.cpp:60:3:60:22 | Store : void | aliasing.cpp:60:3:60:22 | Chi [m1] : void |
-| aliasing.cpp:60:11:60:20 | call to user_input : void | aliasing.cpp:60:3:60:22 | Store : void |
-| aliasing.cpp:61:13:61:14 | Store [m1] : void | aliasing.cpp:62:14:62:15 | m1 |
-| aliasing.cpp:79:3:79:22 | Store : void | aliasing.cpp:80:12:80:13 | m1 |
-| aliasing.cpp:79:11:79:20 | call to user_input : void | aliasing.cpp:79:3:79:22 | Store : void |
-| aliasing.cpp:79:11:79:20 | call to user_input : void | aliasing.cpp:80:12:80:13 | m1 |
-| aliasing.cpp:86:3:86:21 | Store : void | aliasing.cpp:87:12:87:13 | m1 |
-| aliasing.cpp:86:10:86:19 | call to user_input : void | aliasing.cpp:86:3:86:21 | Store : void |
-| aliasing.cpp:86:10:86:19 | call to user_input : void | aliasing.cpp:87:12:87:13 | m1 |
-| aliasing.cpp:92:3:92:23 | Store : void | aliasing.cpp:93:12:93:13 | m1 |
-| aliasing.cpp:92:12:92:21 | call to user_input : void | aliasing.cpp:92:3:92:23 | Store : void |
-| aliasing.cpp:92:12:92:21 | call to user_input : void | aliasing.cpp:93:12:93:13 | m1 |
-| struct_init.c:20:20:20:29 | Store : void | struct_init.c:22:11:22:11 | a |
-| struct_init.c:20:20:20:29 | call to user_input : void | struct_init.c:20:20:20:29 | Store : void |
-| struct_init.c:20:20:20:29 | call to user_input : void | struct_init.c:22:11:22:11 | a |
-| struct_init.c:27:7:27:16 | Store : void | struct_init.c:31:23:31:23 | a |
-| struct_init.c:27:7:27:16 | call to user_input : void | struct_init.c:27:7:27:16 | Store : void |
-| struct_init.c:27:7:27:16 | call to user_input : void | struct_init.c:31:23:31:23 | a |
+| aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 |
+| aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 |
+| aliasing.cpp:60:3:60:22 | Chi [m1] | aliasing.cpp:61:13:61:14 | Store [m1] |
+| aliasing.cpp:60:3:60:22 | Store | aliasing.cpp:60:3:60:22 | Chi [m1] |
+| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | Store |
+| aliasing.cpp:61:13:61:14 | Store [m1] | aliasing.cpp:62:14:62:15 | m1 |
+| aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 |
+| aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 |
+| aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 |
+| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a |
+| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a |
nodes
-| aliasing.cpp:37:3:37:24 | Store : void | semmle.label | Store : void |
-| aliasing.cpp:37:13:37:22 | call to user_input : void | semmle.label | call to user_input : void |
+| aliasing.cpp:37:13:37:22 | call to user_input | semmle.label | call to user_input |
| aliasing.cpp:38:11:38:12 | m1 | semmle.label | m1 |
-| aliasing.cpp:42:3:42:22 | Store : void | semmle.label | Store : void |
-| aliasing.cpp:42:11:42:20 | call to user_input : void | semmle.label | call to user_input : void |
+| aliasing.cpp:42:11:42:20 | call to user_input | semmle.label | call to user_input |
| aliasing.cpp:43:13:43:14 | m1 | semmle.label | m1 |
-| aliasing.cpp:60:3:60:22 | Chi [m1] : void | semmle.label | Chi [m1] : void |
-| aliasing.cpp:60:3:60:22 | Store : void | semmle.label | Store : void |
-| aliasing.cpp:60:11:60:20 | call to user_input : void | semmle.label | call to user_input : void |
-| aliasing.cpp:61:13:61:14 | Store [m1] : void | semmle.label | Store [m1] : void |
+| aliasing.cpp:60:3:60:22 | Chi [m1] | semmle.label | Chi [m1] |
+| aliasing.cpp:60:3:60:22 | Store | semmle.label | Store |
+| aliasing.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input |
+| aliasing.cpp:61:13:61:14 | Store [m1] | semmle.label | Store [m1] |
| aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 |
-| aliasing.cpp:79:3:79:22 | Store : void | semmle.label | Store : void |
-| aliasing.cpp:79:11:79:20 | call to user_input : void | semmle.label | call to user_input : void |
+| aliasing.cpp:79:11:79:20 | call to user_input | semmle.label | call to user_input |
| aliasing.cpp:80:12:80:13 | m1 | semmle.label | m1 |
-| aliasing.cpp:86:3:86:21 | Store : void | semmle.label | Store : void |
-| aliasing.cpp:86:10:86:19 | call to user_input : void | semmle.label | call to user_input : void |
+| aliasing.cpp:86:10:86:19 | call to user_input | semmle.label | call to user_input |
| aliasing.cpp:87:12:87:13 | m1 | semmle.label | m1 |
-| aliasing.cpp:92:3:92:23 | Store : void | semmle.label | Store : void |
-| aliasing.cpp:92:12:92:21 | call to user_input : void | semmle.label | call to user_input : void |
+| aliasing.cpp:92:12:92:21 | call to user_input | semmle.label | call to user_input |
| aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 |
-| struct_init.c:20:20:20:29 | Store : void | semmle.label | Store : void |
-| struct_init.c:20:20:20:29 | call to user_input : void | semmle.label | call to user_input : void |
+| struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input |
| struct_init.c:22:11:22:11 | a | semmle.label | a |
-| struct_init.c:27:7:27:16 | Store : void | semmle.label | Store : void |
-| struct_init.c:27:7:27:16 | call to user_input : void | semmle.label | call to user_input : void |
+| struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input |
| struct_init.c:31:23:31:23 | a | semmle.label | a |
#select
-| aliasing.cpp:38:11:38:12 | m1 | aliasing.cpp:37:13:37:22 | call to user_input : void | aliasing.cpp:38:11:38:12 | m1 | m1 flows from $@ | aliasing.cpp:37:13:37:22 | call to user_input : void | call to user_input : void |
-| aliasing.cpp:43:13:43:14 | m1 | aliasing.cpp:42:11:42:20 | call to user_input : void | aliasing.cpp:43:13:43:14 | m1 | m1 flows from $@ | aliasing.cpp:42:11:42:20 | call to user_input : void | call to user_input : void |
-| aliasing.cpp:62:14:62:15 | m1 | aliasing.cpp:60:11:60:20 | call to user_input : void | aliasing.cpp:62:14:62:15 | m1 | m1 flows from $@ | aliasing.cpp:60:11:60:20 | call to user_input : void | call to user_input : void |
-| aliasing.cpp:80:12:80:13 | m1 | aliasing.cpp:79:11:79:20 | call to user_input : void | aliasing.cpp:80:12:80:13 | m1 | m1 flows from $@ | aliasing.cpp:79:11:79:20 | call to user_input : void | call to user_input : void |
-| aliasing.cpp:87:12:87:13 | m1 | aliasing.cpp:86:10:86:19 | call to user_input : void | aliasing.cpp:87:12:87:13 | m1 | m1 flows from $@ | aliasing.cpp:86:10:86:19 | call to user_input : void | call to user_input : void |
-| aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input : void | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input : void | call to user_input : void |
-| struct_init.c:22:11:22:11 | a | struct_init.c:20:20:20:29 | call to user_input : void | struct_init.c:22:11:22:11 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input : void | call to user_input : void |
-| struct_init.c:31:23:31:23 | a | struct_init.c:27:7:27:16 | call to user_input : void | struct_init.c:31:23:31:23 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input : void | call to user_input : void |
+| aliasing.cpp:38:11:38:12 | m1 | aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | m1 flows from $@ | aliasing.cpp:37:13:37:22 | call to user_input | call to user_input |
+| aliasing.cpp:43:13:43:14 | m1 | aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | m1 flows from $@ | aliasing.cpp:42:11:42:20 | call to user_input | call to user_input |
+| aliasing.cpp:62:14:62:15 | m1 | aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:62:14:62:15 | m1 | m1 flows from $@ | aliasing.cpp:60:11:60:20 | call to user_input | call to user_input |
+| aliasing.cpp:80:12:80:13 | m1 | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | m1 flows from $@ | aliasing.cpp:79:11:79:20 | call to user_input | call to user_input |
+| aliasing.cpp:87:12:87:13 | m1 | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | m1 flows from $@ | aliasing.cpp:86:10:86:19 | call to user_input | call to user_input |
+| aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input | call to user_input |
+| struct_init.c:22:11:22:11 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input |
+| struct_init.c:31:23:31:23 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input |
diff --git a/cpp/ql/test/library-tests/literals/literals/literals.expected b/cpp/ql/test/library-tests/literals/literals/literals.expected
index 4e640c9b2dc..a3fd43a7f04 100644
--- a/cpp/ql/test/library-tests/literals/literals/literals.expected
+++ b/cpp/ql/test/library-tests/literals/literals/literals.expected
@@ -2,10 +2,10 @@
| literals.c:3:13:3:16 | 1.0 |
| literals.c:4:13:4:16 | 1.0 |
| literals.c:5:13:5:16 | 1.0 |
-| literals.c:6:13:6:16 | (1.0,1.0i) |
-| literals.c:7:13:7:16 | (1.0,1.0i) |
-| literals.c:8:13:8:16 | (1.0,1.0i) |
-| literals.c:9:13:9:16 | (1.0,1.0i) |
+| literals.c:6:13:6:16 | (0.0,1.0i) |
+| literals.c:7:13:7:16 | (0.0,1.0i) |
+| literals.c:8:13:8:16 | (0.0,1.0i) |
+| literals.c:9:13:9:16 | (0.0,1.0i) |
| literals.c:10:13:10:16 | 1.0 |
| literals.c:11:13:11:16 | 1.0 |
| literals.c:12:13:12:16 | 1.0 |
diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected
index 1ccd19e1ad9..a05e392ecf2 100644
--- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected
+++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected
@@ -17,14 +17,10 @@ edges
| funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 |
| funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 |
| funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 |
-| funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 |
-| funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 |
| funcsLocal.c:31:19:31:21 | fgets output argument | funcsLocal.c:32:9:32:10 | (const char *)... |
| funcsLocal.c:31:19:31:21 | fgets output argument | funcsLocal.c:32:9:32:10 | i4 |
| funcsLocal.c:31:19:31:21 | i41 | funcsLocal.c:32:9:32:10 | (const char *)... |
| funcsLocal.c:31:19:31:21 | i41 | funcsLocal.c:32:9:32:10 | i4 |
-| funcsLocal.c:32:9:32:10 | i4 | funcsLocal.c:32:9:32:10 | (const char *)... |
-| funcsLocal.c:32:9:32:10 | i4 | funcsLocal.c:32:9:32:10 | i4 |
| funcsLocal.c:36:7:36:8 | gets output argument | funcsLocal.c:37:9:37:10 | (const char *)... |
| funcsLocal.c:36:7:36:8 | gets output argument | funcsLocal.c:37:9:37:10 | i5 |
| funcsLocal.c:36:7:36:8 | i5 | funcsLocal.c:37:9:37:10 | (const char *)... |
@@ -35,14 +31,10 @@ edges
| funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 |
| funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 |
| funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 |
-| funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 |
-| funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 |
| funcsLocal.c:41:18:41:20 | gets output argument | funcsLocal.c:42:9:42:10 | (const char *)... |
| funcsLocal.c:41:18:41:20 | gets output argument | funcsLocal.c:42:9:42:10 | i6 |
| funcsLocal.c:41:18:41:20 | i61 | funcsLocal.c:42:9:42:10 | (const char *)... |
| funcsLocal.c:41:18:41:20 | i61 | funcsLocal.c:42:9:42:10 | i6 |
-| funcsLocal.c:42:9:42:10 | i6 | funcsLocal.c:42:9:42:10 | (const char *)... |
-| funcsLocal.c:42:9:42:10 | i6 | funcsLocal.c:42:9:42:10 | i6 |
nodes
| funcsLocal.c:16:8:16:9 | fread output argument | semmle.label | fread output argument |
| funcsLocal.c:16:8:16:9 | i1 | semmle.label | i1 |
From de29d93edeb6a19d7debdebf4a8fc8848d58eee3 Mon Sep 17 00:00:00 2001
From: Robert Marsh
Date: Mon, 13 Apr 2020 14:39:51 -0700
Subject: [PATCH 0112/1298] C++: add method qldoc for Comment.qll
---
cpp/ql/src/semmle/code/cpp/Comments.qll | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/cpp/ql/src/semmle/code/cpp/Comments.qll b/cpp/ql/src/semmle/code/cpp/Comments.qll
index e517f8e7b0e..1558bf95477 100644
--- a/cpp/ql/src/semmle/code/cpp/Comments.qll
+++ b/cpp/ql/src/semmle/code/cpp/Comments.qll
@@ -1,3 +1,5 @@
+
+
import semmle.code.cpp.Location
import semmle.code.cpp.Element
@@ -13,8 +15,20 @@ class Comment extends Locatable, @comment {
override Location getLocation() { comments(underlyingElement(this), _, result) }
+ /**
+ * Gets the text of this comment, including the opening `//` or `/*`, and the closing `*``/` if
+ * present.
+ */
string getContents() { comments(underlyingElement(this), result, _) }
+ /**
+ * Gets the AST element this comment is associated with. For example, the comment in the
+ * following code is associated with the declaration of `j`.
+ * ```
+ * int i;
+ * int j; // Comment on j
+ * ```
+ */
Element getCommentedElement() {
commentbinding(underlyingElement(this), unresolveElement(result))
}
From d065389a6b082c675aba0da941d09a92249791bd Mon Sep 17 00:00:00 2001
From: Robert Marsh
Date: Mon, 13 Apr 2020 14:41:25 -0700
Subject: [PATCH 0113/1298] C++: add method commetns in Compilation.qll
---
cpp/ql/src/semmle/code/cpp/Compilation.qll | 1 +
1 file changed, 1 insertion(+)
diff --git a/cpp/ql/src/semmle/code/cpp/Compilation.qll b/cpp/ql/src/semmle/code/cpp/Compilation.qll
index 02d962844c8..42c2009a751 100644
--- a/cpp/ql/src/semmle/code/cpp/Compilation.qll
+++ b/cpp/ql/src/semmle/code/cpp/Compilation.qll
@@ -40,6 +40,7 @@ class Compilation extends @compilation {
/** Gets a file compiled during this invocation. */
File getAFileCompiled() { result = getFileCompiled(_) }
+ /** Gets the `i`th file compiled during this invocation */
File getFileCompiled(int i) { compilation_compiling_files(this, i, unresolveElement(result)) }
/**
From f24c4e51c51a10f2b55115663f8fd043b728555c Mon Sep 17 00:00:00 2001
From: Robert Marsh
Date: Mon, 13 Apr 2020 14:58:30 -0700
Subject: [PATCH 0114/1298] C++: add method qldoc in Diagnostics.qll
---
cpp/ql/src/semmle/code/cpp/Diagnostics.qll | 1 +
1 file changed, 1 insertion(+)
diff --git a/cpp/ql/src/semmle/code/cpp/Diagnostics.qll b/cpp/ql/src/semmle/code/cpp/Diagnostics.qll
index f03f03783c1..37459602c03 100644
--- a/cpp/ql/src/semmle/code/cpp/Diagnostics.qll
+++ b/cpp/ql/src/semmle/code/cpp/Diagnostics.qll
@@ -11,6 +11,7 @@ class Diagnostic extends Locatable, @diagnostic {
/** Gets the error code for this compiler message. */
string getTag() { diagnostics(underlyingElement(this), _, result, _, _, _) }
+ /** Holds if `s` is the error code for this compiler message. */
predicate hasTag(string s) { this.getTag() = s }
/**
From 603a3af19b62b2f171ec4d34f8bc56250578b434 Mon Sep 17 00:00:00 2001
From: Dave Bartolomeo
Date: Mon, 13 Apr 2020 18:09:44 -0400
Subject: [PATCH 0115/1298] C++: Treat implicit end of body of non`-void`
function as `Unreached`
When the extractor can't prove that control flow will never reach the end of a non-`void`-returning function without reaching an explicit `return` statement, it inserts an implicit `return` without an operand. If control actually reaches this point, the behavior is undefined.
We were previously generating invalid IR for these implicit `return` statements, because the lack of an operand meant that there was no definition of the return value variable along that path. Instead, I've changed the IR generation to emit an `Unreached` instruction for the implicit `return`. This ensures that we don't create a control flow edge from the end of the body to the function epilogue.
The change to the range analysis test avoids having that test depend on the previous bad IR behavior, while still preserving the original spirit of the test.
---
.../raw/internal/TranslatedFunction.qll | 7 +++-
.../raw/internal/TranslatedStmt.qll | 38 ++++++++++++++++++-
.../library-tests/ir/ir/PrintAST.expected | 17 +++++++++
cpp/ql/test/library-tests/ir/ir/ir.cpp | 12 ++++--
.../test/library-tests/ir/ir/raw_ir.expected | 30 +++++++++++++++
.../rangeanalysis/RangeAnalysis.expected | 2 +-
.../rangeanalysis/rangeanalysis/test.cpp | 8 ++--
7 files changed, 104 insertions(+), 10 deletions(-)
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll
index 1bfc1c8275f..c93562c1390 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll
@@ -49,6 +49,11 @@ CppType getEllipsisVariablePRValueType() {
CppType getEllipsisVariableGLValueType() { result = getTypeForGLValue(any(UnknownType t)) }
+/**
+ * Holds if the function returns a value, as opposed to returning `void`.
+ */
+predicate hasReturnValue(Function func) { not func.getUnspecifiedType() instanceof VoidType }
+
/**
* Represents the IR translation of a function. This is the root elements for
* all other elements associated with this function.
@@ -312,7 +317,7 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
/**
* Holds if the function has a non-`void` return type.
*/
- final predicate hasReturnValue() { not func.getUnspecifiedType() instanceof VoidType }
+ final predicate hasReturnValue() { hasReturnValue(func) }
/**
* Gets the single `UnmodeledDefinition` instruction for this function.
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll
index 88a7d4c99ea..f7d060c7c64 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll
@@ -131,6 +131,9 @@ abstract class TranslatedReturnStmt extends TranslatedStmt {
}
}
+/**
+ * The IR translation of a `return` statement that returns a value.
+ */
class TranslatedReturnValueStmt extends TranslatedReturnStmt, TranslatedVariableInitialization {
TranslatedReturnValueStmt() { stmt.hasExpr() }
@@ -147,8 +150,14 @@ class TranslatedReturnValueStmt extends TranslatedReturnStmt, TranslatedVariable
final override IRVariable getIRVariable() { result = getEnclosingFunction().getReturnVariable() }
}
+/**
+ * The IR translation of a `return` statement that does not return a value. This includes implicit
+ * return statements at the end of `void`-returning functions.
+ */
class TranslatedReturnVoidStmt extends TranslatedReturnStmt {
- TranslatedReturnVoidStmt() { not stmt.hasExpr() }
+ TranslatedReturnVoidStmt() {
+ not stmt.hasExpr() and not hasReturnValue(stmt.getEnclosingFunction())
+ }
override TranslatedElement getChild(int id) { none() }
@@ -169,6 +178,33 @@ class TranslatedReturnVoidStmt extends TranslatedReturnStmt {
override Instruction getChildSuccessor(TranslatedElement child) { none() }
}
+/**
+ * The IR translation of an implicit `return` statement generated by the extractor to handle control
+ * flow that reaches the end of a non-`void`-returning function body. Since such control flow
+ * produces undefined behavior, we simply generate an `Unreached` instruction to prevent that flow
+ * from continuing on to pollute other analysis. The assumption is that the developer is certain
+ * that the implicit `return` is unreachable, even if the compiler cannot prove it.
+ */
+class TranslatedUnreachableReturnStmt extends TranslatedReturnStmt {
+ TranslatedUnreachableReturnStmt() {
+ not stmt.hasExpr() and hasReturnValue(stmt.getEnclosingFunction())
+ }
+
+ override TranslatedElement getChild(int id) { none() }
+
+ override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) }
+
+ override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
+ tag = OnlyInstructionTag() and
+ opcode instanceof Opcode::Unreached and
+ resultType = getVoidType()
+ }
+
+ override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
+
+ override Instruction getChildSuccessor(TranslatedElement child) { none() }
+}
+
/**
* The IR translation of a C++ `try` statement.
*/
diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
index e218b6daf47..e2a02352f0f 100644
--- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
+++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
@@ -8750,6 +8750,23 @@ ir.cpp:
# 1286| Type = [PointerType] A *
# 1286| ValueCategory = prvalue
# 1287| 12: [ReturnStmt] return ...
+# 1289| [TopLevelFunction] int missingReturnValue(bool, int)
+# 1289| params:
+# 1289| 0: [Parameter] b
+# 1289| Type = [BoolType] bool
+# 1289| 1: [Parameter] x
+# 1289| Type = [IntType] int
+# 1289| body: [Block] { ... }
+# 1290| 0: [IfStmt] if (...) ...
+# 1290| 0: [VariableAccess] b
+# 1290| Type = [BoolType] bool
+# 1290| ValueCategory = prvalue(load)
+# 1290| 1: [Block] { ... }
+# 1291| 0: [ReturnStmt] return ...
+# 1291| 0: [VariableAccess] x
+# 1291| Type = [IntType] int
+# 1291| ValueCategory = prvalue(load)
+# 1293| 1: [ReturnStmt] return ...
perf-regression.cpp:
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
# 4| params:
diff --git a/cpp/ql/test/library-tests/ir/ir/ir.cpp b/cpp/ql/test/library-tests/ir/ir/ir.cpp
index ec40d944789..e40c4c095d6 100644
--- a/cpp/ql/test/library-tests/ir/ir/ir.cpp
+++ b/cpp/ql/test/library-tests/ir/ir/ir.cpp
@@ -1249,10 +1249,10 @@ char *strcpy(char *destination, const char *source);
char *strcat(char *destination, const char *source);
void test_strings(char *s1, char *s2) {
- char buffer[1024] = {0};
+ char buffer[1024] = {0};
- strcpy(buffer, s1);
- strcat(buffer, s2);
+ strcpy(buffer, s1);
+ strcat(buffer, s2);
}
struct A {
@@ -1286,4 +1286,10 @@ void test_static_member_functions(int int_arg, A* a_arg) {
getAnInstanceOfA()->static_member_without_def();
}
+int missingReturnValue(bool b, int x) {
+ if (b) {
+ return x;
+ }
+}
+
// semmle-extractor-options: -std=c++17 --clang
diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected
index d74ce2920b0..344269ec7db 100644
--- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected
+++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected
@@ -6631,6 +6631,36 @@ ir.cpp:
# 1270| v1270_14(void) = AliasedUse : ~mu1270_4
# 1270| v1270_15(void) = ExitFunction :
+# 1289| int missingReturnValue(bool, int)
+# 1289| Block 0
+# 1289| v1289_1(void) = EnterFunction :
+# 1289| mu1289_2(unknown) = AliasedDefinition :
+# 1289| mu1289_3(unknown) = InitializeNonLocal :
+# 1289| mu1289_4(unknown) = UnmodeledDefinition :
+# 1289| r1289_5(glval) = VariableAddress[b] :
+# 1289| mu1289_6(bool) = InitializeParameter[b] : &:r1289_5
+# 1289| r1289_7(glval) = VariableAddress[x] :
+# 1289| mu1289_8(int) = InitializeParameter[x] : &:r1289_7
+# 1290| r1290_1(glval) = VariableAddress[b] :
+# 1290| r1290_2(bool) = Load : &:r1290_1, ~mu1289_4
+# 1290| v1290_3(void) = ConditionalBranch : r1290_2
+#-----| False -> Block 1
+#-----| True -> Block 2
+
+# 1293| Block 1
+# 1293| v1293_1(void) = Unreached :
+
+# 1291| Block 2
+# 1291| r1291_1(glval) = VariableAddress[#return] :
+# 1291| r1291_2(glval) = VariableAddress[x] :
+# 1291| r1291_3(int) = Load : &:r1291_2, ~mu1289_4
+# 1291| mu1291_4(int) = Store : &:r1291_1, r1291_3
+# 1289| r1289_9(glval) = VariableAddress[#return] :
+# 1289| v1289_10(void) = ReturnValue : &:r1289_9, ~mu1289_4
+# 1289| v1289_11(void) = UnmodeledUse : mu*
+# 1289| v1289_12(void) = AliasedUse : ~mu1289_4
+# 1289| v1289_13(void) = ExitFunction :
+
perf-regression.cpp:
# 6| void Big::Big()
# 6| Block 0
diff --git a/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected b/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected
index be768a4a82f..78ff3edde3d 100644
--- a/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected
+++ b/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected
@@ -35,7 +35,7 @@
| test.cpp:97:10:97:10 | Load: x | file://:0:0:0:0 | 0 | 1 | false | CompareLT: ... < ... | test.cpp:94:7:94:11 | test.cpp:94:7:94:11 |
| test.cpp:100:10:100:10 | Load: x | file://:0:0:0:0 | 0 | 1 | true | CompareLE: ... <= ... | test.cpp:99:7:99:12 | test.cpp:99:7:99:12 |
| test.cpp:102:10:102:10 | Load: x | file://:0:0:0:0 | 0 | 2 | false | CompareLE: ... <= ... | test.cpp:99:7:99:12 | test.cpp:99:7:99:12 |
-| test.cpp:107:5:107:10 | Phi: test10 | test.cpp:114:3:114:6 | Phi: call to sink | -1 | true | CompareLT: ... < ... | test.cpp:115:18:115:22 | test.cpp:115:18:115:22 |
+| test.cpp:117:10:117:10 | Load: i | test.cpp:114:3:114:6 | Phi: call to sink | -1 | true | CompareLT: ... < ... | test.cpp:116:7:116:11 | test.cpp:116:7:116:11 |
| test.cpp:130:10:130:10 | Load: i | file://:0:0:0:0 | 0 | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
| test.cpp:140:10:140:10 | Store: i | file://:0:0:0:0 | 0 | 1 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
| test.cpp:140:10:140:10 | Store: i | test.cpp:135:16:135:16 | InitializeParameter: x | 0 | false | CompareLT: ... < ... | test.cpp:139:11:139:15 | test.cpp:139:11:139:15 |
diff --git a/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/test.cpp b/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/test.cpp
index d31de1d2b80..87653c2fa43 100644
--- a/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/test.cpp
+++ b/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/test.cpp
@@ -104,7 +104,7 @@ void test9(int x) {
}
// Phi nodes as bounds
-int test10(int y, int z, bool use_y) {
+void test10(int y, int z, bool use_y) {
int x;
if(use_y) {
x = y;
@@ -112,9 +112,9 @@ int test10(int y, int z, bool use_y) {
x = z;
}
sink();
- for(int i = 0; i < x; i++) {
- return i;
- }
+ int i = source();
+ if (i < x)
+ sink(i);
}
// Irreducible CFGs
From 1bde11706efd98d0b89a1d7e2d357f3d0d6e9be6 Mon Sep 17 00:00:00 2001
From: Dave Bartolomeo
Date: Mon, 13 Apr 2020 18:37:47 -0400
Subject: [PATCH 0116/1298] C++: Connect `InitializeIndirection` to
`UnmodeledDefinition`
The IR generation for `InitializeIndirection` currently connects its load operand to the result of the corresponding `InitializeParameter` instruction. This isn't exactly wrong, but it doesn't fit the IR invariant of "All unmodeled uses consume `UnmodeledDefinition`". Our current code doesn't care, because we just throw away all of the existing def-use information, modeled or otherwise, when we build unaliased SSA. However, some upcoming SSA changes don't work correctly if this invariant is broken.
I've added the trivial IR generation change, along with a new sanity query.
---
.../implementation/aliased_ssa/IRSanity.qll | 20 ++++++
.../cpp/ir/implementation/raw/IRSanity.qll | 20 ++++++
.../raw/internal/TranslatedFunction.qll | 2 +-
.../implementation/unaliased_ssa/IRSanity.qll | 20 ++++++
.../ir/ir/aliased_ssa_sanity.expected | 1 +
.../ir/ir/aliased_ssa_sanity_unsound.expected | 1 +
.../test/library-tests/ir/ir/raw_ir.expected | 68 +++++++++----------
.../library-tests/ir/ir/raw_sanity.expected | 1 +
.../ir/ir/unaliased_ssa_sanity.expected | 1 +
.../ir/unaliased_ssa_sanity_unsound.expected | 1 +
.../ir/ssa/aliased_ssa_sanity.expected | 1 +
.../ssa/aliased_ssa_sanity_unsound.expected | 1 +
.../ir/ssa/unaliased_ssa_sanity.expected | 1 +
.../ssa/unaliased_ssa_sanity_unsound.expected | 1 +
.../csharp/ir/implementation/raw/IRSanity.qll | 20 ++++++
.../implementation/unaliased_ssa/IRSanity.qll | 20 ++++++
16 files changed, 144 insertions(+), 35 deletions(-)
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll
index 94d0192fe18..edf4bc00259 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll
@@ -149,6 +149,26 @@ module InstructionSanity {
count(instr.getBlock().getAPredecessor()) < 2
}
+ /**
+ * Holds if a memory operand is connected to a definition with an unmodeled result, other than
+ * `UnmodeledDefinition` itself.
+ */
+ query predicate memoryOperandDefinitionIsUnmodeled(
+ Instruction instr, string message, IRFunction func, string funcText
+ ) {
+ exists(MemoryOperand operand, Instruction def |
+ operand = instr.getAnOperand() and
+ not operand instanceof UnmodeledUseOperand and
+ def = operand.getAnyDef() and
+ not def.isResultModeled() and
+ not def instanceof UnmodeledDefinitionInstruction and
+ message =
+ "Memory operand definition has unmodeled result, but is not the `UnmodeledDefinition` instruction in function '$@'" and
+ func = instr.getEnclosingIRFunction() and
+ funcText = Language::getIdentityString(func.getFunction())
+ )
+ }
+
/**
* Holds if operand `operand` consumes a value that was defined in
* a different function.
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll
index 94d0192fe18..edf4bc00259 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll
@@ -149,6 +149,26 @@ module InstructionSanity {
count(instr.getBlock().getAPredecessor()) < 2
}
+ /**
+ * Holds if a memory operand is connected to a definition with an unmodeled result, other than
+ * `UnmodeledDefinition` itself.
+ */
+ query predicate memoryOperandDefinitionIsUnmodeled(
+ Instruction instr, string message, IRFunction func, string funcText
+ ) {
+ exists(MemoryOperand operand, Instruction def |
+ operand = instr.getAnOperand() and
+ not operand instanceof UnmodeledUseOperand and
+ def = operand.getAnyDef() and
+ not def.isResultModeled() and
+ not def instanceof UnmodeledDefinitionInstruction and
+ message =
+ "Memory operand definition has unmodeled result, but is not the `UnmodeledDefinition` instruction in function '$@'" and
+ func = instr.getEnclosingIRFunction() and
+ funcText = Language::getIdentityString(func.getFunction())
+ )
+ }
+
/**
* Holds if operand `operand` consumes a value that was defined in
* a different function.
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll
index 1bfc1c8275f..04d366c6340 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll
@@ -454,7 +454,7 @@ abstract class TranslatedParameter extends TranslatedElement {
result = getInstruction(InitializerVariableAddressTag())
or
operandTag instanceof LoadOperandTag and
- result = getInstruction(InitializerStoreTag())
+ result = getTranslatedFunction(getFunction()).getUnmodeledDefinitionInstruction()
)
or
tag = InitializerIndirectStoreTag() and
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll
index 94d0192fe18..edf4bc00259 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll
@@ -149,6 +149,26 @@ module InstructionSanity {
count(instr.getBlock().getAPredecessor()) < 2
}
+ /**
+ * Holds if a memory operand is connected to a definition with an unmodeled result, other than
+ * `UnmodeledDefinition` itself.
+ */
+ query predicate memoryOperandDefinitionIsUnmodeled(
+ Instruction instr, string message, IRFunction func, string funcText
+ ) {
+ exists(MemoryOperand operand, Instruction def |
+ operand = instr.getAnOperand() and
+ not operand instanceof UnmodeledUseOperand and
+ def = operand.getAnyDef() and
+ not def.isResultModeled() and
+ not def instanceof UnmodeledDefinitionInstruction and
+ message =
+ "Memory operand definition has unmodeled result, but is not the `UnmodeledDefinition` instruction in function '$@'" and
+ func = instr.getEnclosingIRFunction() and
+ funcText = Language::getIdentityString(func.getFunction())
+ )
+ }
+
/**
* Holds if operand `operand` consumes a value that was defined in
* a different function.
diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected
index 735555b5a4b..3a1a30265b2 100644
--- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected
+++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected
@@ -13,6 +13,7 @@ instructionWithoutSuccessor
ambiguousSuccessors
unexplainedLoop
unnecessaryPhiInstruction
+memoryOperandDefinitionIsUnmodeled
operandAcrossFunctions
instructionWithoutUniqueBlock
containsLoopOfForwardEdges
diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity_unsound.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity_unsound.expected
index 735555b5a4b..3a1a30265b2 100644
--- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity_unsound.expected
+++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity_unsound.expected
@@ -13,6 +13,7 @@ instructionWithoutSuccessor
ambiguousSuccessors
unexplainedLoop
unnecessaryPhiInstruction
+memoryOperandDefinitionIsUnmodeled
operandAcrossFunctions
instructionWithoutUniqueBlock
containsLoopOfForwardEdges
diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected
index d74ce2920b0..b782cd8d741 100644
--- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected
+++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected
@@ -69,7 +69,7 @@ bad_asts.cpp:
# 26| mu26_4(unknown) = UnmodeledDefinition :
# 26| r26_5(glval) = VariableAddress[a] :
# 26| mu26_6(Point &) = InitializeParameter[a] : &:r26_5
-# 26| r26_7(Point &) = Load : &:r26_5, ~mu26_6
+# 26| r26_7(Point &) = Load : &:r26_5, ~mu26_4
# 26| mu26_8(unknown) = InitializeIndirection[a] : &:r26_7
# 27| r27_1(glval) = VariableAddress[b] :
# 27| r27_2(glval) = VariableAddress[a] :
@@ -769,7 +769,7 @@ ir.cpp:
# 153| mu153_4(unknown) = UnmodeledDefinition :
# 153| r153_5(glval) = VariableAddress[p] :
# 153| mu153_6(int *) = InitializeParameter[p] : &:r153_5
-# 153| r153_7(int *) = Load : &:r153_5, ~mu153_6
+# 153| r153_7(int *) = Load : &:r153_5, ~mu153_4
# 153| mu153_8(unknown) = InitializeIndirection[p] : &:r153_7
# 153| r153_9(glval) = VariableAddress[i] :
# 153| mu153_10(int) = InitializeParameter[i] : &:r153_9
@@ -850,7 +850,7 @@ ir.cpp:
# 171| mu171_4(unknown) = UnmodeledDefinition :
# 171| r171_5(glval) = VariableAddress[p] :
# 171| mu171_6(int *) = InitializeParameter[p] : &:r171_5
-# 171| r171_7(int *) = Load : &:r171_5, ~mu171_6
+# 171| r171_7(int *) = Load : &:r171_5, ~mu171_4
# 171| mu171_8(unknown) = InitializeIndirection[p] : &:r171_7
# 171| r171_9(glval) = VariableAddress[i] :
# 171| mu171_10(int) = InitializeParameter[i] : &:r171_9
@@ -972,11 +972,11 @@ ir.cpp:
# 193| mu193_4(unknown) = UnmodeledDefinition :
# 193| r193_5(glval) = VariableAddress[p] :
# 193| mu193_6(int *) = InitializeParameter[p] : &:r193_5
-# 193| r193_7(int *) = Load : &:r193_5, ~mu193_6
+# 193| r193_7(int *) = Load : &:r193_5, ~mu193_4
# 193| mu193_8(unknown) = InitializeIndirection[p] : &:r193_7
# 193| r193_9(glval) = VariableAddress[q] :
# 193| mu193_10(int *) = InitializeParameter[q] : &:r193_9
-# 193| r193_11(int *) = Load : &:r193_9, ~mu193_10
+# 193| r193_11(int *) = Load : &:r193_9, ~mu193_4
# 193| mu193_12(unknown) = InitializeIndirection[q] : &:r193_11
# 194| r194_1(glval) = VariableAddress[b] :
# 194| mu194_2(bool) = Uninitialized[b] : &:r194_1
@@ -1038,7 +1038,7 @@ ir.cpp:
# 204| mu204_4(unknown) = UnmodeledDefinition :
# 204| r204_5(glval) = VariableAddress[p] :
# 204| mu204_6(int *) = InitializeParameter[p] : &:r204_5
-# 204| r204_7(int *) = Load : &:r204_5, ~mu204_6
+# 204| r204_7(int *) = Load : &:r204_5, ~mu204_4
# 204| mu204_8(unknown) = InitializeIndirection[p] : &:r204_7
# 205| r205_1(glval) = VariableAddress[q] :
# 205| mu205_2(int *) = Uninitialized[q] : &:r205_1
@@ -1672,7 +1672,7 @@ ir.cpp:
# 341| mu341_4(unknown) = UnmodeledDefinition :
# 341| r341_5(glval) = VariableAddress[p] :
# 341| mu341_6(int *) = InitializeParameter[p] : &:r341_5
-# 341| r341_7(int *) = Load : &:r341_5, ~mu341_6
+# 341| r341_7(int *) = Load : &:r341_5, ~mu341_4
# 341| mu341_8(unknown) = InitializeIndirection[p] : &:r341_7
# 342| r342_1(int) = Constant[1] :
# 342| r342_2(glval) = VariableAddress[p] :
@@ -2951,11 +2951,11 @@ ir.cpp:
# 622| mu622_4(unknown) = UnmodeledDefinition :
# 622| r622_5(glval) = VariableAddress[r] :
# 622| mu622_6(String &) = InitializeParameter[r] : &:r622_5
-# 622| r622_7(String &) = Load : &:r622_5, ~mu622_6
+# 622| r622_7(String &) = Load : &:r622_5, ~mu622_4
# 622| mu622_8(unknown) = InitializeIndirection[r] : &:r622_7
# 622| r622_9(glval) = VariableAddress[p] :
# 622| mu622_10(String *) = InitializeParameter[p] : &:r622_9
-# 622| r622_11(String *) = Load : &:r622_9, ~mu622_10
+# 622| r622_11(String *) = Load : &:r622_9, ~mu622_4
# 622| mu622_12(unknown) = InitializeIndirection[p] : &:r622_11
# 622| r622_13(glval) = VariableAddress[s] :
# 622| mu622_14(String) = InitializeParameter[s] : &:r622_13
@@ -3191,7 +3191,7 @@ ir.cpp:
# 675| mu675_4(unknown) = UnmodeledDefinition :
# 675| r675_5(glval) = VariableAddress[r] :
# 675| mu675_6(int &) = InitializeParameter[r] : &:r675_5
-# 675| r675_7(int &) = Load : &:r675_5, ~mu675_6
+# 675| r675_7(int &) = Load : &:r675_5, ~mu675_4
# 675| mu675_8(unknown) = InitializeIndirection[r] : &:r675_7
# 676| r676_1(glval) = VariableAddress[#return] :
# 676| r676_2(glval) = VariableAddress[r] :
@@ -3384,7 +3384,7 @@ ir.cpp:
# 715| mu715_4(unknown) = UnmodeledDefinition :
# 715| r715_5(glval) = VariableAddress[x] :
# 715| mu715_6(void *) = InitializeParameter[x] : &:r715_5
-# 715| r715_7(void *) = Load : &:r715_5, ~mu715_6
+# 715| r715_7(void *) = Load : &:r715_5, ~mu715_4
# 715| mu715_8(unknown) = InitializeIndirection[x] : &:r715_7
# 715| r715_9(glval) = VariableAddress[y] :
# 715| mu715_10(char) = InitializeParameter[y] : &:r715_9
@@ -3508,7 +3508,7 @@ ir.cpp:
# 735| Block 10
# 735| r735_2(glval) = VariableAddress[s] :
# 735| mu735_3(char *) = InitializeParameter[s] : &:r735_2
-# 735| r735_4(char *) = Load : &:r735_2, ~mu735_3
+# 735| r735_4(char *) = Load : &:r735_2, ~mu724_4
# 735| mu735_5(unknown) = InitializeIndirection[s] : &:r735_4
# 736| r736_1(glval) = VariableAddress[#throw736:5] :
# 736| mu736_2(String) = Uninitialized[#throw736:5] : &:r736_1
@@ -3531,7 +3531,7 @@ ir.cpp:
# 738| Block 12
# 738| r738_2(glval) = VariableAddress[e] :
# 738| mu738_3(String &) = InitializeParameter[e] : &:r738_2
-# 738| r738_4(String &) = Load : &:r738_2, ~mu738_3
+# 738| r738_4(String &) = Load : &:r738_2, ~mu724_4
# 738| mu738_5(unknown) = InitializeIndirection[e] : &:r738_4
# 738| v738_6(void) = NoOp :
#-----| Goto -> Block 14
@@ -3555,7 +3555,7 @@ ir.cpp:
# 745| r745_5(glval) = InitializeThis :
#-----| r0_1(glval) = VariableAddress[p#0] :
#-----| mu0_2(Base &) = InitializeParameter[p#0] : &:r0_1
-#-----| r0_3(Base &) = Load : &:r0_1, ~mu0_2
+#-----| r0_3(Base &) = Load : &:r0_1, ~mu745_4
#-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3
#-----| r0_5(Base *) = CopyValue : r745_5
#-----| r0_6(glval) = FieldAddress[base_s] : r0_5
@@ -3594,7 +3594,7 @@ ir.cpp:
# 745| r745_5(glval) = InitializeThis :
#-----| r0_1(glval) = VariableAddress[p#0] :
#-----| mu0_2(Base &) = InitializeParameter[p#0] : &:r0_1
-#-----| r0_3(Base &) = Load : &:r0_1, ~mu0_2
+#-----| r0_3(Base &) = Load : &:r0_1, ~mu745_4
#-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3
# 745| r745_6(glval) = FieldAddress[base_s] : r745_5
# 745| r745_7(glval) = FunctionAddress[String] :
@@ -3652,7 +3652,7 @@ ir.cpp:
# 754| r754_5(glval) = InitializeThis :
#-----| r0_1(glval) = VariableAddress[p#0] :
#-----| mu0_2(Middle &) = InitializeParameter[p#0] : &:r0_1
-#-----| r0_3(Middle &) = Load : &:r0_1, ~mu0_2
+#-----| r0_3(Middle &) = Load : &:r0_1, ~mu754_4
#-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3
#-----| r0_5(Middle *) = CopyValue : r754_5
#-----| r0_6(Base *) = ConvertToNonVirtualBase[Middle : Base] : r0_5
@@ -3752,7 +3752,7 @@ ir.cpp:
# 763| r763_5(glval) = InitializeThis :
#-----| r0_1(glval) = VariableAddress[p#0] :
#-----| mu0_2(Derived &) = InitializeParameter[p#0] : &:r0_1
-#-----| r0_3(Derived &) = Load : &:r0_1, ~mu0_2
+#-----| r0_3(Derived &) = Load : &:r0_1, ~mu763_4
#-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3
#-----| r0_5(Derived *) = CopyValue : r763_5
#-----| r0_6(Middle *) = ConvertToNonVirtualBase[Derived : Middle] : r0_5
@@ -4483,7 +4483,7 @@ ir.cpp:
# 883| mu883_6(..(*)(..)) = InitializeParameter[pfn] : &:r883_5
# 883| r883_7(glval) = VariableAddress[p] :
# 883| mu883_8(void *) = InitializeParameter[p] : &:r883_7
-# 883| r883_9(void *) = Load : &:r883_7, ~mu883_8
+# 883| r883_9(void *) = Load : &:r883_7, ~mu883_4
# 883| mu883_10(unknown) = InitializeIndirection[p] : &:r883_9
# 884| r884_1(glval<..(*)(..)>) = VariableAddress[pfn] :
# 884| r884_2(..(*)(..)) = Load : &:r884_1, ~mu883_4
@@ -4512,7 +4512,7 @@ ir.cpp:
# 888| mu888_6(int) = InitializeParameter[x] : &:r888_5
# 888| r888_7(glval<__va_list_tag *>) = VariableAddress[args] :
# 888| mu888_8(__va_list_tag *) = InitializeParameter[args] : &:r888_7
-# 888| r888_9(__va_list_tag *) = Load : &:r888_7, ~mu888_8
+# 888| r888_9(__va_list_tag *) = Load : &:r888_7, ~mu888_4
# 888| mu888_10(unknown) = InitializeIndirection[args] : &:r888_9
# 889| r889_1(glval<__va_list_tag[1]>) = VariableAddress[args2] :
# 889| mu889_2(__va_list_tag[1]) = Uninitialized[args2] : &:r889_1
@@ -4561,7 +4561,7 @@ ir.cpp:
# 896| mu896_6(int) = InitializeParameter[x] : &:r896_5
# 896| r896_7(glval) = VariableAddress[#ellipsis] :
# 896| mu896_8(unknown[11]) = InitializeParameter[#ellipsis] : &:r896_7
-# 896| r896_9(unknown[11]) = Load : &:r896_7, ~mu896_8
+# 896| r896_9(unknown[11]) = Load : &:r896_7, ~mu896_4
# 896| mu896_10(unknown) = InitializeIndirection[#ellipsis] : &:r896_9
# 897| r897_1(glval<__va_list_tag[1]>) = VariableAddress[args] :
# 897| mu897_2(__va_list_tag[1]) = Uninitialized[args] : &:r897_1
@@ -5048,7 +5048,7 @@ ir.cpp:
# 996| mu996_4(unknown) = UnmodeledDefinition :
# 996| r996_5(glval) = VariableAddress[a] :
# 996| mu996_6(int *) = InitializeParameter[a] : &:r996_5
-# 996| r996_7(int *) = Load : &:r996_5, ~mu996_6
+# 996| r996_7(int *) = Load : &:r996_5, ~mu996_4
# 996| mu996_8(unknown) = InitializeIndirection[a] : &:r996_7
# 996| r996_9(glval<..(*)(..)>) = VariableAddress[fn] :
# 996| mu996_10(..(*)(..)) = InitializeParameter[fn] : &:r996_9
@@ -5222,7 +5222,7 @@ ir.cpp:
# 1040| mu1040_6(int) = InitializeParameter[x] : &:r1040_5
# 1040| r1040_7(glval) = VariableAddress[s] :
# 1040| mu1040_8(String &) = InitializeParameter[s] : &:r1040_7
-# 1040| r1040_9(String &) = Load : &:r1040_7, ~mu1040_8
+# 1040| r1040_9(String &) = Load : &:r1040_7, ~mu1040_4
# 1040| mu1040_10(unknown) = InitializeIndirection[s] : &:r1040_9
# 1041| r1041_1(glval) = VariableAddress[lambda_empty] :
# 1041| r1041_2(glval) = VariableAddress[#temp1041:23] :
@@ -5645,7 +5645,7 @@ ir.cpp:
# 1077| mu1077_4(unknown) = UnmodeledDefinition :
# 1077| r1077_5(glval &>) = VariableAddress[v] :
# 1077| mu1077_6(vector &) = InitializeParameter[v] : &:r1077_5
-# 1077| r1077_7(vector &) = Load : &:r1077_5, ~mu1077_6
+# 1077| r1077_7(vector &) = Load : &:r1077_5, ~mu1077_4
# 1077| mu1077_8(unknown) = InitializeIndirection[v] : &:r1077_7
# 1078| r1078_1(glval &>) = VariableAddress[(__range)] :
# 1078| r1078_2(glval &>) = VariableAddress[v] :
@@ -5838,13 +5838,13 @@ ir.cpp:
# 1113| mu1113_4(unknown) = UnmodeledDefinition :
# 1113| r1113_5(glval) = VariableAddress[a] :
# 1113| mu1113_6(unsigned int &) = InitializeParameter[a] : &:r1113_5
-# 1113| r1113_7(unsigned int &) = Load : &:r1113_5, ~mu1113_6
+# 1113| r1113_7(unsigned int &) = Load : &:r1113_5, ~mu1113_4
# 1113| mu1113_8(unknown) = InitializeIndirection[a] : &:r1113_7
# 1113| r1113_9(glval) = VariableAddress[b] :
# 1113| mu1113_10(unsigned int) = InitializeParameter[b] : &:r1113_9
# 1113| r1113_11(glval) = VariableAddress[c] :
# 1113| mu1113_12(unsigned int &) = InitializeParameter[c] : &:r1113_11
-# 1113| r1113_13(unsigned int &) = Load : &:r1113_11, ~mu1113_12
+# 1113| r1113_13(unsigned int &) = Load : &:r1113_11, ~mu1113_4
# 1113| mu1113_14(unknown) = InitializeIndirection[c] : &:r1113_13
# 1113| r1113_15(glval) = VariableAddress[d] :
# 1113| mu1113_16(unsigned int) = InitializeParameter[d] : &:r1113_15
@@ -6008,7 +6008,7 @@ ir.cpp:
# 1153| Block 10
# 1153| r1153_2(glval) = VariableAddress[s] :
# 1153| mu1153_3(char *) = InitializeParameter[s] : &:r1153_2
-# 1153| r1153_4(char *) = Load : &:r1153_2, ~mu1153_3
+# 1153| r1153_4(char *) = Load : &:r1153_2, ~mu1142_4
# 1153| mu1153_5(unknown) = InitializeIndirection[s] : &:r1153_4
# 1154| r1154_1(glval) = VariableAddress[#throw1154:5] :
# 1154| mu1154_2(String) = Uninitialized[#throw1154:5] : &:r1154_1
@@ -6031,7 +6031,7 @@ ir.cpp:
# 1156| Block 12
# 1156| r1156_2(glval) = VariableAddress[e] :
# 1156| mu1156_3(String &) = InitializeParameter[e] : &:r1156_2
-# 1156| r1156_4(String &) = Load : &:r1156_2, ~mu1156_3
+# 1156| r1156_4(String &) = Load : &:r1156_2, ~mu1142_4
# 1156| mu1156_5(unknown) = InitializeIndirection[e] : &:r1156_4
# 1156| v1156_6(void) = NoOp :
#-----| Goto -> Block 13
@@ -6385,7 +6385,7 @@ ir.cpp:
# 1240| mu1240_4(unknown) = UnmodeledDefinition :
# 1240| r1240_5(glval) = VariableAddress[dynamic] :
# 1240| mu1240_6(char *) = InitializeParameter[dynamic] : &:r1240_5
-# 1240| r1240_7(char *) = Load : &:r1240_5, ~mu1240_6
+# 1240| r1240_7(char *) = Load : &:r1240_5, ~mu1240_4
# 1240| mu1240_8(unknown) = InitializeIndirection[dynamic] : &:r1240_7
# 1241| r1241_1(glval) = VariableAddress[a#init] :
# 1241| r1241_2(bool) = Load : &:r1241_1, ~mu1240_4
@@ -6461,11 +6461,11 @@ ir.cpp:
# 1251| mu1251_4(unknown) = UnmodeledDefinition :
# 1251| r1251_5(glval) = VariableAddress[s1] :
# 1251| mu1251_6(char *) = InitializeParameter[s1] : &:r1251_5
-# 1251| r1251_7(char *) = Load : &:r1251_5, ~mu1251_6
+# 1251| r1251_7(char *) = Load : &:r1251_5, ~mu1251_4
# 1251| mu1251_8(unknown) = InitializeIndirection[s1] : &:r1251_7
# 1251| r1251_9(glval) = VariableAddress[s2] :
# 1251| mu1251_10(char *) = InitializeParameter[s2] : &:r1251_9
-# 1251| r1251_11(char *) = Load : &:r1251_9, ~mu1251_10
+# 1251| r1251_11(char *) = Load : &:r1251_9, ~mu1251_4
# 1251| mu1251_12(unknown) = InitializeIndirection[s2] : &:r1251_11
# 1252| r1252_1(glval) = VariableAddress[buffer] :
# 1252| mu1252_2(char[1024]) = Uninitialized[buffer] : &:r1252_1
@@ -6512,7 +6512,7 @@ ir.cpp:
# 1261| mu1261_4(unknown) = UnmodeledDefinition :
# 1261| r1261_5(glval) = VariableAddress[a] :
# 1261| mu1261_6(A *) = InitializeParameter[a] : &:r1261_5
-# 1261| r1261_7(A *) = Load : &:r1261_5, ~mu1261_6
+# 1261| r1261_7(A *) = Load : &:r1261_5, ~mu1261_4
# 1261| mu1261_8(unknown) = InitializeIndirection[a] : &:r1261_7
# 1261| r1261_9(glval) = VariableAddress[x] :
# 1261| mu1261_10(int) = InitializeParameter[x] : &:r1261_9
@@ -6539,7 +6539,7 @@ ir.cpp:
# 1270| mu1270_6(int) = InitializeParameter[int_arg] : &:r1270_5
# 1270| r1270_7(glval) = VariableAddress[a_arg] :
# 1270| mu1270_8(A *) = InitializeParameter[a_arg] : &:r1270_7
-# 1270| r1270_9(A *) = Load : &:r1270_7, ~mu1270_8
+# 1270| r1270_9(A *) = Load : &:r1270_7, ~mu1270_4
# 1270| mu1270_10(unknown) = InitializeIndirection[a_arg] : &:r1270_9
# 1271| r1271_1(glval) = VariableAddress[c] :
# 1271| mu1271_2(C) = Uninitialized[c] : &:r1271_1
@@ -6686,7 +6686,7 @@ struct_init.cpp:
# 16| mu16_4(unknown) = UnmodeledDefinition :
# 16| r16_5(glval) = VariableAddress[info] :
# 16| mu16_6(Info *) = InitializeParameter[info] : &:r16_5
-# 16| r16_7(Info *) = Load : &:r16_5, ~mu16_6
+# 16| r16_7(Info *) = Load : &:r16_5, ~mu16_4
# 16| mu16_8(unknown) = InitializeIndirection[info] : &:r16_7
# 17| r17_1(glval) = VariableAddress[info] :
# 17| r17_2(Info *) = Load : &:r17_1, ~mu16_4
@@ -6766,7 +6766,7 @@ struct_init.cpp:
# 36| mu36_4(unknown) = UnmodeledDefinition :
# 36| r36_5(glval) = VariableAddress[name1] :
# 36| mu36_6(char *) = InitializeParameter[name1] : &:r36_5
-# 36| r36_7(char *) = Load : &:r36_5, ~mu36_6
+# 36| r36_7(char *) = Load : &:r36_5, ~mu36_4
# 36| mu36_8(unknown) = InitializeIndirection[name1] : &:r36_7
# 37| r37_1(glval) = VariableAddress[static_infos#init] :
# 37| r37_2(bool) = Load : &:r37_1, ~mu36_4
diff --git a/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected b/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected
index 735555b5a4b..3a1a30265b2 100644
--- a/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected
+++ b/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected
@@ -13,6 +13,7 @@ instructionWithoutSuccessor
ambiguousSuccessors
unexplainedLoop
unnecessaryPhiInstruction
+memoryOperandDefinitionIsUnmodeled
operandAcrossFunctions
instructionWithoutUniqueBlock
containsLoopOfForwardEdges
diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected
index 735555b5a4b..3a1a30265b2 100644
--- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected
+++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected
@@ -13,6 +13,7 @@ instructionWithoutSuccessor
ambiguousSuccessors
unexplainedLoop
unnecessaryPhiInstruction
+memoryOperandDefinitionIsUnmodeled
operandAcrossFunctions
instructionWithoutUniqueBlock
containsLoopOfForwardEdges
diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity_unsound.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity_unsound.expected
index 735555b5a4b..3a1a30265b2 100644
--- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity_unsound.expected
+++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity_unsound.expected
@@ -13,6 +13,7 @@ instructionWithoutSuccessor
ambiguousSuccessors
unexplainedLoop
unnecessaryPhiInstruction
+memoryOperandDefinitionIsUnmodeled
operandAcrossFunctions
instructionWithoutUniqueBlock
containsLoopOfForwardEdges
diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected
index 1e78ae87f40..e2db1e65034 100644
--- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected
+++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected
@@ -9,6 +9,7 @@ instructionWithoutSuccessor
ambiguousSuccessors
unexplainedLoop
unnecessaryPhiInstruction
+memoryOperandDefinitionIsUnmodeled
operandAcrossFunctions
instructionWithoutUniqueBlock
containsLoopOfForwardEdges
diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity_unsound.expected
index 1e78ae87f40..e2db1e65034 100644
--- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity_unsound.expected
+++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity_unsound.expected
@@ -9,6 +9,7 @@ instructionWithoutSuccessor
ambiguousSuccessors
unexplainedLoop
unnecessaryPhiInstruction
+memoryOperandDefinitionIsUnmodeled
operandAcrossFunctions
instructionWithoutUniqueBlock
containsLoopOfForwardEdges
diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected
index 1e78ae87f40..e2db1e65034 100644
--- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected
+++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected
@@ -9,6 +9,7 @@ instructionWithoutSuccessor
ambiguousSuccessors
unexplainedLoop
unnecessaryPhiInstruction
+memoryOperandDefinitionIsUnmodeled
operandAcrossFunctions
instructionWithoutUniqueBlock
containsLoopOfForwardEdges
diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity_unsound.expected
index 1e78ae87f40..e2db1e65034 100644
--- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity_unsound.expected
+++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity_unsound.expected
@@ -9,6 +9,7 @@ instructionWithoutSuccessor
ambiguousSuccessors
unexplainedLoop
unnecessaryPhiInstruction
+memoryOperandDefinitionIsUnmodeled
operandAcrossFunctions
instructionWithoutUniqueBlock
containsLoopOfForwardEdges
diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll
index 94d0192fe18..edf4bc00259 100644
--- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll
+++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll
@@ -149,6 +149,26 @@ module InstructionSanity {
count(instr.getBlock().getAPredecessor()) < 2
}
+ /**
+ * Holds if a memory operand is connected to a definition with an unmodeled result, other than
+ * `UnmodeledDefinition` itself.
+ */
+ query predicate memoryOperandDefinitionIsUnmodeled(
+ Instruction instr, string message, IRFunction func, string funcText
+ ) {
+ exists(MemoryOperand operand, Instruction def |
+ operand = instr.getAnOperand() and
+ not operand instanceof UnmodeledUseOperand and
+ def = operand.getAnyDef() and
+ not def.isResultModeled() and
+ not def instanceof UnmodeledDefinitionInstruction and
+ message =
+ "Memory operand definition has unmodeled result, but is not the `UnmodeledDefinition` instruction in function '$@'" and
+ func = instr.getEnclosingIRFunction() and
+ funcText = Language::getIdentityString(func.getFunction())
+ )
+ }
+
/**
* Holds if operand `operand` consumes a value that was defined in
* a different function.
diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll
index 94d0192fe18..edf4bc00259 100644
--- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll
+++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll
@@ -149,6 +149,26 @@ module InstructionSanity {
count(instr.getBlock().getAPredecessor()) < 2
}
+ /**
+ * Holds if a memory operand is connected to a definition with an unmodeled result, other than
+ * `UnmodeledDefinition` itself.
+ */
+ query predicate memoryOperandDefinitionIsUnmodeled(
+ Instruction instr, string message, IRFunction func, string funcText
+ ) {
+ exists(MemoryOperand operand, Instruction def |
+ operand = instr.getAnOperand() and
+ not operand instanceof UnmodeledUseOperand and
+ def = operand.getAnyDef() and
+ not def.isResultModeled() and
+ not def instanceof UnmodeledDefinitionInstruction and
+ message =
+ "Memory operand definition has unmodeled result, but is not the `UnmodeledDefinition` instruction in function '$@'" and
+ func = instr.getEnclosingIRFunction() and
+ funcText = Language::getIdentityString(func.getFunction())
+ )
+ }
+
/**
* Holds if operand `operand` consumes a value that was defined in
* a different function.
From 10824f961280f538d9064773486a22ceec882fb4 Mon Sep 17 00:00:00 2001
From: Robert Marsh
Date: Mon, 13 Apr 2020 15:22:30 -0700
Subject: [PATCH 0117/1298] C++: add method qldoc in Class.qll
---
cpp/ql/src/semmle/code/cpp/Class.qll | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/cpp/ql/src/semmle/code/cpp/Class.qll b/cpp/ql/src/semmle/code/cpp/Class.qll
index 67a2d11ff24..5aa9f43f48b 100644
--- a/cpp/ql/src/semmle/code/cpp/Class.qll
+++ b/cpp/ql/src/semmle/code/cpp/Class.qll
@@ -458,6 +458,15 @@ class Class extends UserType {
exists(ClassDerivation d | d.getDerivedClass() = this and d = result)
}
+ /**
+ * Gets class derivation number `index` of this class/struct, for example the
+ * `public B` is derivation 1 in the following code:
+ * ```
+ * class D : public A, public B, public C {
+ * ...
+ * };
+ * ```
+ */
ClassDerivation getDerivation(int index) {
exists(ClassDerivation d | d.getDerivedClass() = this and d.getIndex() = index and d = result)
}
@@ -900,6 +909,22 @@ class AbstractClass extends Class {
class TemplateClass extends Class {
TemplateClass() { usertypes(underlyingElement(this), _, 6) }
+ /**
+ * Gets a class instantiated from this template.
+ *
+ * For example for `MyTemplateClass` in the following code, the results are
+ * `MyTemplateClass` and `MyTemplateClass`:
+ * ```
+ * template
+ * class MyTemplateClass {
+ * ...
+ * };
+ *
+ * MyTemplateClass instance;
+ *
+ * MyTemplateClass instance;
+ * ```
+ */
Class getAnInstantiation() {
result.isConstructedFrom(this) and
exists(result.getATemplateArgument())
From a9b88b6eaa8ff4aca7b43b5c9d59e4e8eae0dadf Mon Sep 17 00:00:00 2001
From: Tom Hvitved
Date: Mon, 6 Apr 2020 20:49:19 +0200
Subject: [PATCH 0118/1298] C#: Update data flow tests
---
.../csharp/dataflow/LibraryTypeDataFlow.qll | 5 +
.../dataflow/global/DataFlow.expected | 18 +-
.../dataflow/global/DataFlowEdges.expected | 3816 -----------
.../dataflow/global/DataFlowEdges.ql | 17 -
.../dataflow/global/DataFlowPath.expected | 182 +-
.../dataflow/global/GetAnOutNode.expected | 135 +-
.../dataflow/global/GlobalDataFlow.cs | 56 +-
.../dataflow/global/TaintTracking.expected | 32 +-
.../global/TaintTrackingEdges.expected | 5782 -----------------
.../dataflow/global/TaintTrackingEdges.ql | 17 -
.../global/TaintTrackingPath.expected | 346 +-
.../library/LibraryTypeDataFlow.expected | 2 +
.../dataflow/local/DataFlow.expected | 20 +-
.../dataflow/local/DataFlowStep.expected | 950 ++-
.../dataflow/local/LocalDataFlow.cs | 119 +-
.../dataflow/local/TaintTracking.expected | 111 +-
.../dataflow/local/TaintTrackingStep.expected | 1204 ++--
17 files changed, 1342 insertions(+), 11470 deletions(-)
delete mode 100644 csharp/ql/test/library-tests/dataflow/global/DataFlowEdges.expected
delete mode 100644 csharp/ql/test/library-tests/dataflow/global/DataFlowEdges.ql
delete mode 100644 csharp/ql/test/library-tests/dataflow/global/TaintTrackingEdges.expected
delete mode 100644 csharp/ql/test/library-tests/dataflow/global/TaintTrackingEdges.ql
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll b/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll
index 87eee2a80be..26b6e5f7b96 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll
@@ -755,6 +755,11 @@ class IEnumerableFlow extends LibraryTypeDataFlow {
sink = TCallableFlowSinkReturn()
)
or
+ name = "AsQueryable" and
+ arity = 1 and
+ source = TCallableFlowSourceArg(0) and
+ sink = TCallableFlowSinkReturn()
+ or
name = "Average" and
(
arity = 2 and
diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected
index 38c978be390..ca81fb55904 100644
--- a/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected
+++ b/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected
@@ -28,15 +28,15 @@
| GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 |
| GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 |
| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 |
-| GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 |
-| GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 |
-| GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 |
-| GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 |
-| GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 |
-| GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 |
-| GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 |
-| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 |
-| GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 |
+| GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 |
+| GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 |
+| GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 |
+| GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 |
+| GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 |
+| GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 |
+| GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 |
+| GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 |
+| GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 |
| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x |
| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x |
| Splitting.cs:11:19:11:19 | access to local variable x |
diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlowEdges.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlowEdges.expected
deleted file mode 100644
index b386a148705..00000000000
--- a/csharp/ql/test/library-tests/dataflow/global/DataFlowEdges.expected
+++ /dev/null
@@ -1,3816 +0,0 @@
-| Capture.cs:7:10:7:11 | this : Capture | Capture.cs:14:9:14:18 | this access |
-| Capture.cs:7:10:7:11 | this : Capture | Capture.cs:14:9:14:18 | this access : Capture |
-| Capture.cs:7:10:7:11 | this : Capture | Capture.cs:25:9:25:18 | this access |
-| Capture.cs:7:10:7:11 | this : Capture | Capture.cs:25:9:25:18 | this access : Capture |
-| Capture.cs:7:10:7:11 | this : Capture | Capture.cs:49:9:49:27 | this access |
-| Capture.cs:7:10:7:11 | this : Capture | Capture.cs:49:9:49:27 | this access : Capture |
-| Capture.cs:7:10:7:11 | this : Capture | Capture.cs:61:9:61:19 | this access |
-| Capture.cs:7:10:7:11 | this : Capture | Capture.cs:61:9:61:19 | this access : Capture |
-| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:14:9:14:20 | [implicit argument] tainted |
-| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:14:9:14:20 | [implicit argument] tainted : String |
-| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:25:9:25:20 | [implicit argument] tainted |
-| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:25:9:25:20 | [implicit argument] tainted : String |
-| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:33:9:33:40 | [implicit argument] tainted |
-| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:33:9:33:40 | [implicit argument] tainted : String |
-| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:61:36:61:42 | access to parameter tainted |
-| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:61:36:61:42 | access to parameter tainted : String |
-| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:11:17:11:32 | SSA def(sink27) |
-| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:11:17:11:32 | SSA def(sink27) |
-| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:11:17:11:32 | SSA def(sink27) : String |
-| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:11:17:11:32 | SSA def(sink27) : String |
-| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:11:26:11:32 | access to parameter tainted |
-| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:11:26:11:32 | access to parameter tainted |
-| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:11:26:11:32 | access to parameter tainted : String |
-| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:11:26:11:32 | access to parameter tainted : String |
-| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:12:19:12:24 | access to local variable sink27 |
-| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:12:19:12:24 | access to local variable sink27 |
-| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:12:19:12:24 | access to local variable sink27 : String |
-| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:12:19:12:24 | access to local variable sink27 : String |
-| Capture.cs:11:17:11:32 | SSA def(sink27) : String | Capture.cs:12:19:12:24 | access to local variable sink27 |
-| Capture.cs:11:17:11:32 | SSA def(sink27) : String | Capture.cs:12:19:12:24 | access to local variable sink27 |
-| Capture.cs:11:17:11:32 | SSA def(sink27) : String | Capture.cs:12:19:12:24 | access to local variable sink27 : String |
-| Capture.cs:11:17:11:32 | SSA def(sink27) : String | Capture.cs:12:19:12:24 | access to local variable sink27 : String |
-| Capture.cs:11:26:11:32 | access to parameter tainted : String | Capture.cs:11:17:11:32 | SSA def(sink27) |
-| Capture.cs:11:26:11:32 | access to parameter tainted : String | Capture.cs:11:17:11:32 | SSA def(sink27) |
-| Capture.cs:11:26:11:32 | access to parameter tainted : String | Capture.cs:11:17:11:32 | SSA def(sink27) : String |
-| Capture.cs:11:26:11:32 | access to parameter tainted : String | Capture.cs:11:17:11:32 | SSA def(sink27) : String |
-| Capture.cs:11:26:11:32 | access to parameter tainted : String | Capture.cs:12:19:12:24 | access to local variable sink27 |
-| Capture.cs:11:26:11:32 | access to parameter tainted : String | Capture.cs:12:19:12:24 | access to local variable sink27 |
-| Capture.cs:11:26:11:32 | access to parameter tainted : String | Capture.cs:12:19:12:24 | access to local variable sink27 : String |
-| Capture.cs:11:26:11:32 | access to parameter tainted : String | Capture.cs:12:19:12:24 | access to local variable sink27 : String |
-| Capture.cs:14:9:14:18 | this access : Capture | Capture.cs:25:9:25:18 | this access |
-| Capture.cs:14:9:14:18 | this access : Capture | Capture.cs:25:9:25:18 | this access : Capture |
-| Capture.cs:14:9:14:18 | this access : Capture | Capture.cs:49:9:49:27 | this access |
-| Capture.cs:14:9:14:18 | this access : Capture | Capture.cs:49:9:49:27 | this access : Capture |
-| Capture.cs:14:9:14:18 | this access : Capture | Capture.cs:61:9:61:19 | this access |
-| Capture.cs:14:9:14:18 | this access : Capture | Capture.cs:61:9:61:19 | this access : Capture |
-| Capture.cs:14:9:14:20 | [implicit argument] tainted : String | Capture.cs:9:9:13:9 | SSA capture def(tainted) |
-| Capture.cs:14:9:14:20 | [implicit argument] tainted : String | Capture.cs:9:9:13:9 | SSA capture def(tainted) : String |
-| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:20:21:20:36 | SSA def(sink28) |
-| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:20:21:20:36 | SSA def(sink28) |
-| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:20:21:20:36 | SSA def(sink28) : String |
-| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:20:21:20:36 | SSA def(sink28) : String |
-| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:20:30:20:36 | access to parameter tainted |
-| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:20:30:20:36 | access to parameter tainted |
-| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:20:30:20:36 | access to parameter tainted : String |
-| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:20:30:20:36 | access to parameter tainted : String |
-| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:21:23:21:28 | access to local variable sink28 |
-| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:21:23:21:28 | access to local variable sink28 |
-| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:21:23:21:28 | access to local variable sink28 : String |
-| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:21:23:21:28 | access to local variable sink28 : String |
-| Capture.cs:20:21:20:36 | SSA def(sink28) : String | Capture.cs:21:23:21:28 | access to local variable sink28 |
-| Capture.cs:20:21:20:36 | SSA def(sink28) : String | Capture.cs:21:23:21:28 | access to local variable sink28 |
-| Capture.cs:20:21:20:36 | SSA def(sink28) : String | Capture.cs:21:23:21:28 | access to local variable sink28 : String |
-| Capture.cs:20:21:20:36 | SSA def(sink28) : String | Capture.cs:21:23:21:28 | access to local variable sink28 : String |
-| Capture.cs:20:30:20:36 | access to parameter tainted : String | Capture.cs:20:21:20:36 | SSA def(sink28) |
-| Capture.cs:20:30:20:36 | access to parameter tainted : String | Capture.cs:20:21:20:36 | SSA def(sink28) |
-| Capture.cs:20:30:20:36 | access to parameter tainted : String | Capture.cs:20:21:20:36 | SSA def(sink28) : String |
-| Capture.cs:20:30:20:36 | access to parameter tainted : String | Capture.cs:20:21:20:36 | SSA def(sink28) : String |
-| Capture.cs:20:30:20:36 | access to parameter tainted : String | Capture.cs:21:23:21:28 | access to local variable sink28 |
-| Capture.cs:20:30:20:36 | access to parameter tainted : String | Capture.cs:21:23:21:28 | access to local variable sink28 |
-| Capture.cs:20:30:20:36 | access to parameter tainted : String | Capture.cs:21:23:21:28 | access to local variable sink28 : String |
-| Capture.cs:20:30:20:36 | access to parameter tainted : String | Capture.cs:21:23:21:28 | access to local variable sink28 : String |
-| Capture.cs:25:9:25:18 | this access : Capture | Capture.cs:49:9:49:27 | this access |
-| Capture.cs:25:9:25:18 | this access : Capture | Capture.cs:49:9:49:27 | this access : Capture |
-| Capture.cs:25:9:25:18 | this access : Capture | Capture.cs:61:9:61:19 | this access |
-| Capture.cs:25:9:25:18 | this access : Capture | Capture.cs:61:9:61:19 | this access : Capture |
-| Capture.cs:25:9:25:20 | [implicit argument] tainted : String | Capture.cs:18:13:22:13 | SSA capture def(tainted) |
-| Capture.cs:25:9:25:20 | [implicit argument] tainted : String | Capture.cs:18:13:22:13 | SSA capture def(tainted) : String |
-| Capture.cs:27:30:32:9 | SSA def(captureIn3) : Func | Capture.cs:33:30:33:39 | access to local variable captureIn3 |
-| Capture.cs:27:30:32:9 | SSA def(captureIn3) : Func | Capture.cs:33:30:33:39 | access to local variable captureIn3 : Func |
-| Capture.cs:27:43:27:45 | arg : String | Capture.cs:31:20:31:22 | access to parameter arg |
-| Capture.cs:27:43:27:45 | arg : String | Capture.cs:31:20:31:22 | access to parameter arg : String |
-| Capture.cs:27:43:32:9 | (...) => ... : Func | Capture.cs:27:30:32:9 | SSA def(captureIn3) |
-| Capture.cs:27:43:32:9 | (...) => ... : Func | Capture.cs:27:30:32:9 | SSA def(captureIn3) : Func |
-| Capture.cs:27:43:32:9 | (...) => ... : Func | Capture.cs:33:30:33:39 | access to local variable captureIn3 |
-| Capture.cs:27:43:32:9 | (...) => ... : Func | Capture.cs:33:30:33:39 | access to local variable captureIn3 : Func |
-| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:29:17:29:32 | SSA def(sink29) |
-| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:29:17:29:32 | SSA def(sink29) |
-| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:29:17:29:32 | SSA def(sink29) : String |
-| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:29:17:29:32 | SSA def(sink29) : String |
-| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:29:26:29:32 | access to parameter tainted |
-| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:29:26:29:32 | access to parameter tainted |
-| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:29:26:29:32 | access to parameter tainted : String |
-| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:29:26:29:32 | access to parameter tainted : String |
-| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:30:19:30:24 | access to local variable sink29 |
-| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:30:19:30:24 | access to local variable sink29 |
-| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:30:19:30:24 | access to local variable sink29 : String |
-| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:30:19:30:24 | access to local variable sink29 : String |
-| Capture.cs:29:17:29:32 | SSA def(sink29) : String | Capture.cs:30:19:30:24 | access to local variable sink29 |
-| Capture.cs:29:17:29:32 | SSA def(sink29) : String | Capture.cs:30:19:30:24 | access to local variable sink29 |
-| Capture.cs:29:17:29:32 | SSA def(sink29) : String | Capture.cs:30:19:30:24 | access to local variable sink29 : String |
-| Capture.cs:29:17:29:32 | SSA def(sink29) : String | Capture.cs:30:19:30:24 | access to local variable sink29 : String |
-| Capture.cs:29:26:29:32 | access to parameter tainted : String | Capture.cs:29:17:29:32 | SSA def(sink29) |
-| Capture.cs:29:26:29:32 | access to parameter tainted : String | Capture.cs:29:17:29:32 | SSA def(sink29) |
-| Capture.cs:29:26:29:32 | access to parameter tainted : String | Capture.cs:29:17:29:32 | SSA def(sink29) : String |
-| Capture.cs:29:26:29:32 | access to parameter tainted : String | Capture.cs:29:17:29:32 | SSA def(sink29) : String |
-| Capture.cs:29:26:29:32 | access to parameter tainted : String | Capture.cs:30:19:30:24 | access to local variable sink29 |
-| Capture.cs:29:26:29:32 | access to parameter tainted : String | Capture.cs:30:19:30:24 | access to local variable sink29 |
-| Capture.cs:29:26:29:32 | access to parameter tainted : String | Capture.cs:30:19:30:24 | access to local variable sink29 : String |
-| Capture.cs:29:26:29:32 | access to parameter tainted : String | Capture.cs:30:19:30:24 | access to local variable sink29 : String |
-| Capture.cs:31:20:31:22 | access to parameter arg : String | Capture.cs:33:30:33:39 | [output] access to local variable captureIn3 |
-| Capture.cs:31:20:31:22 | access to parameter arg : String | Capture.cs:33:30:33:39 | [output] access to local variable captureIn3 : String |
-| Capture.cs:33:9:33:21 | array creation of type String[] : String[] | Capture.cs:27:43:27:45 | arg |
-| Capture.cs:33:9:33:21 | array creation of type String[] : String[] | Capture.cs:27:43:27:45 | arg : String[] |
-| Capture.cs:33:9:33:40 | [implicit argument] tainted : String | Capture.cs:27:43:32:9 | SSA capture def(tainted) |
-| Capture.cs:33:9:33:40 | [implicit argument] tainted : String | Capture.cs:27:43:32:9 | SSA capture def(tainted) : String |
-| Capture.cs:35:9:39:9 | SSA capture def(tainted) : String | Capture.cs:37:17:37:34 | SSA def(nonSink0) |
-| Capture.cs:35:9:39:9 | SSA capture def(tainted) : String | Capture.cs:37:17:37:34 | SSA def(nonSink0) : String |
-| Capture.cs:35:9:39:9 | SSA capture def(tainted) : String | Capture.cs:37:28:37:34 | access to parameter tainted |
-| Capture.cs:35:9:39:9 | SSA capture def(tainted) : String | Capture.cs:37:28:37:34 | access to parameter tainted : String |
-| Capture.cs:35:9:39:9 | SSA capture def(tainted) : String | Capture.cs:38:19:38:26 | access to local variable nonSink0 |
-| Capture.cs:35:9:39:9 | SSA capture def(tainted) : String | Capture.cs:38:19:38:26 | access to local variable nonSink0 : String |
-| Capture.cs:37:17:37:34 | SSA def(nonSink0) : String | Capture.cs:38:19:38:26 | access to local variable nonSink0 |
-| Capture.cs:37:17:37:34 | SSA def(nonSink0) : String | Capture.cs:38:19:38:26 | access to local variable nonSink0 : String |
-| Capture.cs:37:28:37:34 | access to parameter tainted : String | Capture.cs:37:17:37:34 | SSA def(nonSink0) |
-| Capture.cs:37:28:37:34 | access to parameter tainted : String | Capture.cs:37:17:37:34 | SSA def(nonSink0) : String |
-| Capture.cs:37:28:37:34 | access to parameter tainted : String | Capture.cs:38:19:38:26 | access to local variable nonSink0 |
-| Capture.cs:37:28:37:34 | access to parameter tainted : String | Capture.cs:38:19:38:26 | access to local variable nonSink0 : String |
-| Capture.cs:43:13:47:13 | SSA capture def(tainted) : String | Capture.cs:45:21:45:38 | SSA def(nonSink0) |
-| Capture.cs:43:13:47:13 | SSA capture def(tainted) : String | Capture.cs:45:21:45:38 | SSA def(nonSink0) : String |
-| Capture.cs:43:13:47:13 | SSA capture def(tainted) : String | Capture.cs:45:32:45:38 | access to parameter tainted |
-| Capture.cs:43:13:47:13 | SSA capture def(tainted) : String | Capture.cs:45:32:45:38 | access to parameter tainted : String |
-| Capture.cs:43:13:47:13 | SSA capture def(tainted) : String | Capture.cs:46:23:46:30 | access to local variable nonSink0 |
-| Capture.cs:43:13:47:13 | SSA capture def(tainted) : String | Capture.cs:46:23:46:30 | access to local variable nonSink0 : String |
-| Capture.cs:45:21:45:38 | SSA def(nonSink0) : String | Capture.cs:46:23:46:30 | access to local variable nonSink0 |
-| Capture.cs:45:21:45:38 | SSA def(nonSink0) : String | Capture.cs:46:23:46:30 | access to local variable nonSink0 : String |
-| Capture.cs:45:32:45:38 | access to parameter tainted : String | Capture.cs:45:21:45:38 | SSA def(nonSink0) |
-| Capture.cs:45:32:45:38 | access to parameter tainted : String | Capture.cs:45:21:45:38 | SSA def(nonSink0) : String |
-| Capture.cs:45:32:45:38 | access to parameter tainted : String | Capture.cs:46:23:46:30 | access to local variable nonSink0 |
-| Capture.cs:45:32:45:38 | access to parameter tainted : String | Capture.cs:46:23:46:30 | access to local variable nonSink0 : String |
-| Capture.cs:49:9:49:27 | this access : Capture | Capture.cs:61:9:61:19 | this access |
-| Capture.cs:49:9:49:27 | this access : Capture | Capture.cs:61:9:61:19 | this access : Capture |
-| Capture.cs:50:33:50:40 | nonSink0 : String | Capture.cs:52:13:59:14 | [implicit argument] nonSink0 |
-| Capture.cs:50:33:50:40 | nonSink0 : String | Capture.cs:52:13:59:14 | [implicit argument] nonSink0 |
-| Capture.cs:50:33:50:40 | nonSink0 : String | Capture.cs:52:13:59:14 | [implicit argument] nonSink0 : String |
-| Capture.cs:50:33:50:40 | nonSink0 : String | Capture.cs:52:13:59:14 | [implicit argument] nonSink0 : String |
-| Capture.cs:50:50:50:55 | sink39 : String | Capture.cs:52:13:59:14 | [implicit argument] sink39 |
-| Capture.cs:50:50:50:55 | sink39 : String | Capture.cs:52:13:59:14 | [implicit argument] sink39 |
-| Capture.cs:50:50:50:55 | sink39 : String | Capture.cs:52:13:59:14 | [implicit argument] sink39 : String |
-| Capture.cs:50:50:50:55 | sink39 : String | Capture.cs:52:13:59:14 | [implicit argument] sink39 : String |
-| Capture.cs:52:13:59:14 | [implicit argument] nonSink0 : String | Capture.cs:52:23:59:13 | SSA capture def(nonSink0) |
-| Capture.cs:52:13:59:14 | [implicit argument] nonSink0 : String | Capture.cs:52:23:59:13 | SSA capture def(nonSink0) |
-| Capture.cs:52:13:59:14 | [implicit argument] nonSink0 : String | Capture.cs:52:23:59:13 | SSA capture def(nonSink0) : String |
-| Capture.cs:52:13:59:14 | [implicit argument] nonSink0 : String | Capture.cs:52:23:59:13 | SSA capture def(nonSink0) : String |
-| Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | Capture.cs:55:27:58:17 | SSA capture def(sink39) |
-| Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | Capture.cs:55:27:58:17 | SSA capture def(sink39) |
-| Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | Capture.cs:55:27:58:17 | SSA capture def(sink39) : String |
-| Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | Capture.cs:55:27:58:17 | SSA capture def(sink39) : String |
-| Capture.cs:52:23:59:13 | (...) => ... : Action | Capture.cs:202:34:202:34 | a |
-| Capture.cs:52:23:59:13 | (...) => ... : Action | Capture.cs:202:34:202:34 | a : Action |
-| Capture.cs:52:23:59:13 | SSA capture def(nonSink0) : String | Capture.cs:54:23:54:30 | access to parameter nonSink0 |
-| Capture.cs:52:23:59:13 | SSA capture def(nonSink0) : String | Capture.cs:54:23:54:30 | access to parameter nonSink0 |
-| Capture.cs:52:23:59:13 | SSA capture def(nonSink0) : String | Capture.cs:54:23:54:30 | access to parameter nonSink0 : String |
-| Capture.cs:52:23:59:13 | SSA capture def(nonSink0) : String | Capture.cs:54:23:54:30 | access to parameter nonSink0 : String |
-| Capture.cs:55:27:58:17 | (...) => ... : Action | Capture.cs:202:34:202:34 | a |
-| Capture.cs:55:27:58:17 | (...) => ... : Action | Capture.cs:202:34:202:34 | a : Action |
-| Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | Capture.cs:57:27:57:32 | access to parameter sink39 |
-| Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | Capture.cs:57:27:57:32 | access to parameter sink39 |
-| Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | Capture.cs:57:27:57:32 | access to parameter sink39 : String |
-| Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | Capture.cs:57:27:57:32 | access to parameter sink39 : String |
-| Capture.cs:61:21:61:33 | "not tainted" : String | Capture.cs:50:33:50:40 | nonSink0 |
-| Capture.cs:61:21:61:33 | "not tainted" : String | Capture.cs:50:33:50:40 | nonSink0 : String |
-| Capture.cs:61:36:61:42 | access to parameter tainted : String | Capture.cs:50:50:50:55 | sink39 |
-| Capture.cs:61:36:61:42 | access to parameter tainted : String | Capture.cs:50:50:50:55 | sink39 : String |
-| Capture.cs:64:10:64:12 | this : Capture | Capture.cs:71:9:71:19 | this access |
-| Capture.cs:64:10:64:12 | this : Capture | Capture.cs:71:9:71:19 | this access : Capture |
-| Capture.cs:64:10:64:12 | this : Capture | Capture.cs:83:9:83:19 | this access |
-| Capture.cs:64:10:64:12 | this : Capture | Capture.cs:83:9:83:19 | this access : Capture |
-| Capture.cs:64:10:64:12 | this : Capture | Capture.cs:109:9:109:28 | this access |
-| Capture.cs:64:10:64:12 | this : Capture | Capture.cs:109:9:109:28 | this access : Capture |
-| Capture.cs:64:10:64:12 | this : Capture | Capture.cs:121:9:121:33 | this access |
-| Capture.cs:64:10:64:12 | this : Capture | Capture.cs:121:9:121:33 | this access : Capture |
-| Capture.cs:66:25:66:26 | "" : String | Capture.cs:66:16:66:26 | SSA def(sink30) |
-| Capture.cs:66:25:66:26 | "" : String | Capture.cs:66:16:66:26 | SSA def(sink30) : String |
-| Capture.cs:69:13:69:35 | SSA def(sink30) : String | Capture.cs:71:9:71:21 | SSA call def(sink30) |
-| Capture.cs:69:13:69:35 | SSA def(sink30) : String | Capture.cs:71:9:71:21 | SSA call def(sink30) : String |
-| Capture.cs:69:22:69:35 | "taint source" : String | Capture.cs:69:13:69:35 | SSA def(sink30) |
-| Capture.cs:69:22:69:35 | "taint source" : String | Capture.cs:69:13:69:35 | SSA def(sink30) : String |
-| Capture.cs:71:9:71:19 | this access : Capture | Capture.cs:83:9:83:19 | this access |
-| Capture.cs:71:9:71:19 | this access : Capture | Capture.cs:83:9:83:19 | this access : Capture |
-| Capture.cs:71:9:71:19 | this access : Capture | Capture.cs:109:9:109:28 | this access |
-| Capture.cs:71:9:71:19 | this access : Capture | Capture.cs:109:9:109:28 | this access : Capture |
-| Capture.cs:71:9:71:19 | this access : Capture | Capture.cs:121:9:121:33 | this access |
-| Capture.cs:71:9:71:19 | this access : Capture | Capture.cs:121:9:121:33 | this access : Capture |
-| Capture.cs:71:9:71:21 | SSA call def(sink30) : String | Capture.cs:72:15:72:20 | access to local variable sink30 |
-| Capture.cs:71:9:71:21 | SSA call def(sink30) : String | Capture.cs:72:15:72:20 | access to local variable sink30 : String |
-| Capture.cs:74:25:74:26 | "" : String | Capture.cs:74:16:74:26 | SSA def(sink31) |
-| Capture.cs:74:25:74:26 | "" : String | Capture.cs:74:16:74:26 | SSA def(sink31) : String |
-| Capture.cs:79:17:79:39 | SSA def(sink31) : String | Capture.cs:83:9:83:21 | SSA call def(sink31) |
-| Capture.cs:79:17:79:39 | SSA def(sink31) : String | Capture.cs:83:9:83:21 | SSA call def(sink31) : String |
-| Capture.cs:79:26:79:39 | "taint source" : String | Capture.cs:79:17:79:39 | SSA def(sink31) |
-| Capture.cs:79:26:79:39 | "taint source" : String | Capture.cs:79:17:79:39 | SSA def(sink31) : String |
-| Capture.cs:83:9:83:19 | this access : Capture | Capture.cs:109:9:109:28 | this access |
-| Capture.cs:83:9:83:19 | this access : Capture | Capture.cs:109:9:109:28 | this access : Capture |
-| Capture.cs:83:9:83:19 | this access : Capture | Capture.cs:121:9:121:33 | this access |
-| Capture.cs:83:9:83:19 | this access : Capture | Capture.cs:121:9:121:33 | this access : Capture |
-| Capture.cs:83:9:83:21 | SSA call def(sink31) : String | Capture.cs:84:15:84:20 | access to local variable sink31 |
-| Capture.cs:83:9:83:21 | SSA call def(sink31) : String | Capture.cs:84:15:84:20 | access to local variable sink31 : String |
-| Capture.cs:86:25:86:26 | "" : String | Capture.cs:86:16:86:26 | SSA def(sink32) |
-| Capture.cs:86:25:86:26 | "" : String | Capture.cs:86:16:86:26 | SSA def(sink32) : String |
-| Capture.cs:87:30:91:9 | SSA def(captureOut3) : Func | Capture.cs:92:30:92:40 | access to local variable captureOut3 |
-| Capture.cs:87:30:91:9 | SSA def(captureOut3) : Func | Capture.cs:92:30:92:40 | access to local variable captureOut3 : Func |
-| Capture.cs:87:44:87:46 | arg : String | Capture.cs:90:20:90:22 | access to parameter arg |
-| Capture.cs:87:44:87:46 | arg : String | Capture.cs:90:20:90:22 | access to parameter arg : String |
-| Capture.cs:87:44:91:9 | (...) => ... : Func | Capture.cs:87:30:91:9 | SSA def(captureOut3) |
-| Capture.cs:87:44:91:9 | (...) => ... : Func | Capture.cs:87:30:91:9 | SSA def(captureOut3) : Func |
-| Capture.cs:87:44:91:9 | (...) => ... : Func | Capture.cs:92:30:92:40 | access to local variable captureOut3 |
-| Capture.cs:87:44:91:9 | (...) => ... : Func | Capture.cs:92:30:92:40 | access to local variable captureOut3 : Func |
-| Capture.cs:89:13:89:35 | SSA def(sink32) : String | Capture.cs:92:9:92:41 | SSA call def(sink32) |
-| Capture.cs:89:13:89:35 | SSA def(sink32) : String | Capture.cs:92:9:92:41 | SSA call def(sink32) : String |
-| Capture.cs:89:22:89:35 | "taint source" : String | Capture.cs:89:13:89:35 | SSA def(sink32) |
-| Capture.cs:89:22:89:35 | "taint source" : String | Capture.cs:89:13:89:35 | SSA def(sink32) : String |
-| Capture.cs:90:20:90:22 | access to parameter arg : String | Capture.cs:92:30:92:40 | [output] access to local variable captureOut3 |
-| Capture.cs:90:20:90:22 | access to parameter arg : String | Capture.cs:92:30:92:40 | [output] access to local variable captureOut3 : String |
-| Capture.cs:92:9:92:21 | array creation of type String[] : String[] | Capture.cs:87:44:87:46 | arg |
-| Capture.cs:92:9:92:21 | array creation of type String[] : String[] | Capture.cs:87:44:87:46 | arg : String[] |
-| Capture.cs:92:9:92:41 | SSA call def(sink32) : String | Capture.cs:93:15:93:20 | access to local variable sink32 |
-| Capture.cs:92:9:92:41 | SSA call def(sink32) : String | Capture.cs:93:15:93:20 | access to local variable sink32 : String |
-| Capture.cs:95:16:95:28 | SSA def(nonSink0) : String | Capture.cs:100:15:100:22 | access to local variable nonSink0 |
-| Capture.cs:95:16:95:28 | SSA def(nonSink0) : String | Capture.cs:100:15:100:22 | access to local variable nonSink0 : String |
-| Capture.cs:95:16:95:28 | SSA def(nonSink0) : String | Capture.cs:110:15:110:22 | access to local variable nonSink0 |
-| Capture.cs:95:16:95:28 | SSA def(nonSink0) : String | Capture.cs:110:15:110:22 | access to local variable nonSink0 : String |
-| Capture.cs:95:27:95:28 | "" : String | Capture.cs:95:16:95:28 | SSA def(nonSink0) |
-| Capture.cs:95:27:95:28 | "" : String | Capture.cs:95:16:95:28 | SSA def(nonSink0) : String |
-| Capture.cs:95:27:95:28 | "" : String | Capture.cs:100:15:100:22 | access to local variable nonSink0 |
-| Capture.cs:95:27:95:28 | "" : String | Capture.cs:100:15:100:22 | access to local variable nonSink0 : String |
-| Capture.cs:95:27:95:28 | "" : String | Capture.cs:110:15:110:22 | access to local variable nonSink0 |
-| Capture.cs:95:27:95:28 | "" : String | Capture.cs:110:15:110:22 | access to local variable nonSink0 : String |
-| Capture.cs:100:15:100:22 | access to local variable nonSink0 : String | Capture.cs:110:15:110:22 | access to local variable nonSink0 |
-| Capture.cs:100:15:100:22 | access to local variable nonSink0 : String | Capture.cs:110:15:110:22 | access to local variable nonSink0 : String |
-| Capture.cs:109:9:109:28 | this access : Capture | Capture.cs:121:9:121:33 | this access |
-| Capture.cs:109:9:109:28 | this access : Capture | Capture.cs:121:9:121:33 | this access : Capture |
-| Capture.cs:111:25:111:26 | "" : String | Capture.cs:111:16:111:26 | SSA def(sink40) |
-| Capture.cs:111:25:111:26 | "" : String | Capture.cs:111:16:111:26 | SSA def(sink40) : String |
-| Capture.cs:114:23:116:13 | (...) => ... : Action | Capture.cs:202:34:202:34 | a |
-| Capture.cs:114:23:116:13 | (...) => ... : Action | Capture.cs:202:34:202:34 | a : Action |
-| Capture.cs:115:17:115:39 | SSA def(sink40) : String | Capture.cs:121:9:121:35 | SSA call def(sink40) |
-| Capture.cs:115:17:115:39 | SSA def(sink40) : String | Capture.cs:121:9:121:35 | SSA call def(sink40) : String |
-| Capture.cs:115:26:115:39 | "taint source" : String | Capture.cs:115:17:115:39 | SSA def(sink40) |
-| Capture.cs:115:26:115:39 | "taint source" : String | Capture.cs:115:17:115:39 | SSA def(sink40) : String |
-| Capture.cs:117:23:119:13 | (...) => ... : Action | Capture.cs:202:34:202:34 | a |
-| Capture.cs:117:23:119:13 | (...) => ... : Action | Capture.cs:202:34:202:34 | a : Action |
-| Capture.cs:118:17:118:40 | SSA def(nonSink0) : String | Capture.cs:121:9:121:35 | SSA call def(nonSink0) |
-| Capture.cs:118:17:118:40 | SSA def(nonSink0) : String | Capture.cs:121:9:121:35 | SSA call def(nonSink0) : String |
-| Capture.cs:118:28:118:40 | "not tainted" : String | Capture.cs:118:17:118:40 | SSA def(nonSink0) |
-| Capture.cs:118:28:118:40 | "not tainted" : String | Capture.cs:118:17:118:40 | SSA def(nonSink0) : String |
-| Capture.cs:121:9:121:35 | SSA call def(nonSink0) : String | Capture.cs:122:30:122:37 | access to local variable nonSink0 |
-| Capture.cs:121:9:121:35 | SSA call def(nonSink0) : String | Capture.cs:122:30:122:37 | access to local variable nonSink0 : String |
-| Capture.cs:121:9:121:35 | SSA call def(sink40) : String | Capture.cs:122:15:122:20 | access to local variable sink40 |
-| Capture.cs:121:9:121:35 | SSA call def(sink40) : String | Capture.cs:122:15:122:20 | access to local variable sink40 : String |
-| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:132:9:132:23 | this access |
-| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:132:9:132:23 | this access : Capture |
-| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:144:9:144:23 | this access |
-| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:144:9:144:23 | this access : Capture |
-| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:160:22:160:36 | this access |
-| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:160:22:160:36 | this access : Capture |
-| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:168:9:168:23 | this access |
-| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:168:9:168:23 | this access : Capture |
-| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:185:9:185:32 | this access |
-| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:185:9:185:32 | this access : Capture |
-| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:194:22:194:23 | this access |
-| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:194:22:194:23 | this access : Capture |
-| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:196:20:196:21 | this access |
-| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:196:20:196:21 | this access : Capture |
-| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:132:9:132:25 | [implicit argument] tainted |
-| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:132:9:132:25 | [implicit argument] tainted : String |
-| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:144:9:144:25 | [implicit argument] tainted |
-| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:144:9:144:25 | [implicit argument] tainted : String |
-| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:153:9:153:45 | [implicit argument] tainted |
-| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:153:9:153:45 | [implicit argument] tainted : String |
-| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:160:22:160:38 | [implicit argument] tainted |
-| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:160:22:160:38 | [implicit argument] tainted : String |
-| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:168:25:168:31 | access to parameter tainted |
-| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:168:25:168:31 | access to parameter tainted : String |
-| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:194:25:194:31 | access to parameter tainted |
-| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:194:25:194:31 | access to parameter tainted : String |
-| Capture.cs:127:25:127:26 | "" : String | Capture.cs:127:16:127:26 | SSA def(sink33) |
-| Capture.cs:127:25:127:26 | "" : String | Capture.cs:127:16:127:26 | SSA def(sink33) : String |
-| Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | Capture.cs:130:13:130:28 | SSA def(sink33) |
-| Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | Capture.cs:130:13:130:28 | SSA def(sink33) |
-| Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | Capture.cs:130:13:130:28 | SSA def(sink33) : String |
-| Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | Capture.cs:130:13:130:28 | SSA def(sink33) : String |
-| Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | Capture.cs:130:22:130:28 | access to parameter tainted |
-| Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | Capture.cs:130:22:130:28 | access to parameter tainted |
-| Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | Capture.cs:130:22:130:28 | access to parameter tainted : String |
-| Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | Capture.cs:130:22:130:28 | access to parameter tainted : String |
-| Capture.cs:130:13:130:28 | SSA def(sink33) : String | Capture.cs:132:9:132:25 | SSA call def(sink33) |
-| Capture.cs:130:13:130:28 | SSA def(sink33) : String | Capture.cs:132:9:132:25 | SSA call def(sink33) : String |
-| Capture.cs:130:22:130:28 | access to parameter tainted : String | Capture.cs:130:13:130:28 | SSA def(sink33) |
-| Capture.cs:130:22:130:28 | access to parameter tainted : String | Capture.cs:130:13:130:28 | SSA def(sink33) |
-| Capture.cs:130:22:130:28 | access to parameter tainted : String | Capture.cs:130:13:130:28 | SSA def(sink33) : String |
-| Capture.cs:130:22:130:28 | access to parameter tainted : String | Capture.cs:130:13:130:28 | SSA def(sink33) : String |
-| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:144:9:144:23 | this access |
-| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:144:9:144:23 | this access : Capture |
-| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:160:22:160:36 | this access |
-| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:160:22:160:36 | this access : Capture |
-| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:168:9:168:23 | this access |
-| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:168:9:168:23 | this access : Capture |
-| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:185:9:185:32 | this access |
-| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:185:9:185:32 | this access : Capture |
-| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:194:22:194:23 | this access |
-| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:194:22:194:23 | this access : Capture |
-| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:196:20:196:21 | this access |
-| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:196:20:196:21 | this access : Capture |
-| Capture.cs:132:9:132:25 | SSA call def(sink33) : String | Capture.cs:133:15:133:20 | access to local variable sink33 |
-| Capture.cs:132:9:132:25 | SSA call def(sink33) : String | Capture.cs:133:15:133:20 | access to local variable sink33 : String |
-| Capture.cs:132:9:132:25 | [implicit argument] tainted : String | Capture.cs:128:9:131:9 | SSA capture def(tainted) |
-| Capture.cs:132:9:132:25 | [implicit argument] tainted : String | Capture.cs:128:9:131:9 | SSA capture def(tainted) : String |
-| Capture.cs:132:9:132:25 | [implicit argument] tainted : String | Capture.cs:132:9:132:25 | SSA call def(sink33) |
-| Capture.cs:132:9:132:25 | [implicit argument] tainted : String | Capture.cs:132:9:132:25 | SSA call def(sink33) : String |
-| Capture.cs:135:25:135:26 | "" : String | Capture.cs:135:16:135:26 | SSA def(sink34) |
-| Capture.cs:135:25:135:26 | "" : String | Capture.cs:135:16:135:26 | SSA def(sink34) : String |
-| Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | Capture.cs:140:17:140:32 | SSA def(sink34) |
-| Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | Capture.cs:140:17:140:32 | SSA def(sink34) |
-| Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | Capture.cs:140:17:140:32 | SSA def(sink34) : String |
-| Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | Capture.cs:140:17:140:32 | SSA def(sink34) : String |
-| Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | Capture.cs:140:26:140:32 | access to parameter tainted |
-| Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | Capture.cs:140:26:140:32 | access to parameter tainted |
-| Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | Capture.cs:140:26:140:32 | access to parameter tainted : String |
-| Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | Capture.cs:140:26:140:32 | access to parameter tainted : String |
-| Capture.cs:140:17:140:32 | SSA def(sink34) : String | Capture.cs:144:9:144:25 | SSA call def(sink34) |
-| Capture.cs:140:17:140:32 | SSA def(sink34) : String | Capture.cs:144:9:144:25 | SSA call def(sink34) : String |
-| Capture.cs:140:26:140:32 | access to parameter tainted : String | Capture.cs:140:17:140:32 | SSA def(sink34) |
-| Capture.cs:140:26:140:32 | access to parameter tainted : String | Capture.cs:140:17:140:32 | SSA def(sink34) |
-| Capture.cs:140:26:140:32 | access to parameter tainted : String | Capture.cs:140:17:140:32 | SSA def(sink34) : String |
-| Capture.cs:140:26:140:32 | access to parameter tainted : String | Capture.cs:140:17:140:32 | SSA def(sink34) : String |
-| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:160:22:160:36 | this access |
-| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:160:22:160:36 | this access : Capture |
-| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:168:9:168:23 | this access |
-| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:168:9:168:23 | this access : Capture |
-| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:185:9:185:32 | this access |
-| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:185:9:185:32 | this access : Capture |
-| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:194:22:194:23 | this access |
-| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:194:22:194:23 | this access : Capture |
-| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:196:20:196:21 | this access |
-| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:196:20:196:21 | this access : Capture |
-| Capture.cs:144:9:144:25 | SSA call def(sink34) : String | Capture.cs:145:15:145:20 | access to local variable sink34 |
-| Capture.cs:144:9:144:25 | SSA call def(sink34) : String | Capture.cs:145:15:145:20 | access to local variable sink34 : String |
-| Capture.cs:144:9:144:25 | [implicit argument] tainted : String | Capture.cs:138:13:141:13 | SSA capture def(tainted) |
-| Capture.cs:144:9:144:25 | [implicit argument] tainted : String | Capture.cs:138:13:141:13 | SSA capture def(tainted) : String |
-| Capture.cs:144:9:144:25 | [implicit argument] tainted : String | Capture.cs:144:9:144:25 | SSA call def(sink34) |
-| Capture.cs:144:9:144:25 | [implicit argument] tainted : String | Capture.cs:144:9:144:25 | SSA call def(sink34) : String |
-| Capture.cs:147:25:147:26 | "" : String | Capture.cs:147:16:147:26 | SSA def(sink35) |
-| Capture.cs:147:25:147:26 | "" : String | Capture.cs:147:16:147:26 | SSA def(sink35) : String |
-| Capture.cs:148:30:152:9 | SSA def(captureThrough3) : Func | Capture.cs:153:30:153:44 | access to local variable captureThrough3 |
-| Capture.cs:148:30:152:9 | SSA def(captureThrough3) : Func | Capture.cs:153:30:153:44 | access to local variable captureThrough3 : Func |
-| Capture.cs:148:48:148:50 | arg : String | Capture.cs:151:20:151:22 | access to parameter arg |
-| Capture.cs:148:48:148:50 | arg : String | Capture.cs:151:20:151:22 | access to parameter arg : String |
-| Capture.cs:148:48:152:9 | (...) => ... : Func | Capture.cs:148:30:152:9 | SSA def(captureThrough3) |
-| Capture.cs:148:48:152:9 | (...) => ... : Func | Capture.cs:148:30:152:9 | SSA def(captureThrough3) : Func |
-| Capture.cs:148:48:152:9 | (...) => ... : Func | Capture.cs:153:30:153:44 | access to local variable captureThrough3 |
-| Capture.cs:148:48:152:9 | (...) => ... : Func | Capture.cs:153:30:153:44 | access to local variable captureThrough3 : Func |
-| Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | Capture.cs:150:13:150:28 | SSA def(sink35) |
-| Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | Capture.cs:150:13:150:28 | SSA def(sink35) |
-| Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | Capture.cs:150:13:150:28 | SSA def(sink35) : String |
-| Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | Capture.cs:150:13:150:28 | SSA def(sink35) : String |
-| Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | Capture.cs:150:22:150:28 | access to parameter tainted |
-| Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | Capture.cs:150:22:150:28 | access to parameter tainted |
-| Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | Capture.cs:150:22:150:28 | access to parameter tainted : String |
-| Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | Capture.cs:150:22:150:28 | access to parameter tainted : String |
-| Capture.cs:150:13:150:28 | SSA def(sink35) : String | Capture.cs:153:9:153:45 | SSA call def(sink35) |
-| Capture.cs:150:13:150:28 | SSA def(sink35) : String | Capture.cs:153:9:153:45 | SSA call def(sink35) : String |
-| Capture.cs:150:22:150:28 | access to parameter tainted : String | Capture.cs:150:13:150:28 | SSA def(sink35) |
-| Capture.cs:150:22:150:28 | access to parameter tainted : String | Capture.cs:150:13:150:28 | SSA def(sink35) |
-| Capture.cs:150:22:150:28 | access to parameter tainted : String | Capture.cs:150:13:150:28 | SSA def(sink35) : String |
-| Capture.cs:150:22:150:28 | access to parameter tainted : String | Capture.cs:150:13:150:28 | SSA def(sink35) : String |
-| Capture.cs:151:20:151:22 | access to parameter arg : String | Capture.cs:153:30:153:44 | [output] access to local variable captureThrough3 |
-| Capture.cs:151:20:151:22 | access to parameter arg : String | Capture.cs:153:30:153:44 | [output] access to local variable captureThrough3 : String |
-| Capture.cs:153:9:153:21 | array creation of type String[] : String[] | Capture.cs:148:48:148:50 | arg |
-| Capture.cs:153:9:153:21 | array creation of type String[] : String[] | Capture.cs:148:48:148:50 | arg : String[] |
-| Capture.cs:153:9:153:45 | SSA call def(sink35) : String | Capture.cs:154:15:154:20 | access to local variable sink35 |
-| Capture.cs:153:9:153:45 | SSA call def(sink35) : String | Capture.cs:154:15:154:20 | access to local variable sink35 : String |
-| Capture.cs:153:9:153:45 | [implicit argument] tainted : String | Capture.cs:148:48:152:9 | SSA capture def(tainted) |
-| Capture.cs:153:9:153:45 | [implicit argument] tainted : String | Capture.cs:148:48:152:9 | SSA capture def(tainted) : String |
-| Capture.cs:153:9:153:45 | [implicit argument] tainted : String | Capture.cs:153:9:153:45 | SSA call def(sink35) |
-| Capture.cs:153:9:153:45 | [implicit argument] tainted : String | Capture.cs:153:9:153:45 | SSA call def(sink35) : String |
-| Capture.cs:156:9:159:9 | SSA capture def(tainted) : String | Capture.cs:158:20:158:26 | access to parameter tainted |
-| Capture.cs:156:9:159:9 | SSA capture def(tainted) : String | Capture.cs:158:20:158:26 | access to parameter tainted |
-| Capture.cs:156:9:159:9 | SSA capture def(tainted) : String | Capture.cs:158:20:158:26 | access to parameter tainted : String |
-| Capture.cs:156:9:159:9 | SSA capture def(tainted) : String | Capture.cs:158:20:158:26 | access to parameter tainted : String |
-| Capture.cs:158:20:158:26 | access to parameter tainted : String | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 |
-| Capture.cs:158:20:158:26 | access to parameter tainted : String | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String |
-| Capture.cs:160:13:160:38 | SSA def(sink36) : String | Capture.cs:161:15:161:20 | access to local variable sink36 |
-| Capture.cs:160:13:160:38 | SSA def(sink36) : String | Capture.cs:161:15:161:20 | access to local variable sink36 : String |
-| Capture.cs:160:22:160:36 | this access : Capture | Capture.cs:168:9:168:23 | this access |
-| Capture.cs:160:22:160:36 | this access : Capture | Capture.cs:168:9:168:23 | this access : Capture |
-| Capture.cs:160:22:160:36 | this access : Capture | Capture.cs:185:9:185:32 | this access |
-| Capture.cs:160:22:160:36 | this access : Capture | Capture.cs:185:9:185:32 | this access : Capture |
-| Capture.cs:160:22:160:36 | this access : Capture | Capture.cs:194:22:194:23 | this access |
-| Capture.cs:160:22:160:36 | this access : Capture | Capture.cs:194:22:194:23 | this access : Capture |
-| Capture.cs:160:22:160:36 | this access : Capture | Capture.cs:196:20:196:21 | this access |
-| Capture.cs:160:22:160:36 | this access : Capture | Capture.cs:196:20:196:21 | this access : Capture |
-| Capture.cs:160:22:160:38 | [implicit argument] tainted : String | Capture.cs:156:9:159:9 | SSA capture def(tainted) |
-| Capture.cs:160:22:160:38 | [implicit argument] tainted : String | Capture.cs:156:9:159:9 | SSA capture def(tainted) : String |
-| Capture.cs:160:22:160:38 | [implicit argument] tainted : String | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 |
-| Capture.cs:160:22:160:38 | [implicit argument] tainted : String | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String |
-| Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | Capture.cs:160:13:160:38 | SSA def(sink36) |
-| Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | Capture.cs:160:13:160:38 | SSA def(sink36) : String |
-| Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | Capture.cs:161:15:161:20 | access to local variable sink36 |
-| Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | Capture.cs:161:15:161:20 | access to local variable sink36 : String |
-| Capture.cs:163:22:163:23 | "" : String | Capture.cs:163:13:163:23 | SSA def(sink37) |
-| Capture.cs:163:22:163:23 | "" : String | Capture.cs:163:13:163:23 | SSA def(sink37) : String |
-| Capture.cs:164:37:164:37 | p : String | Capture.cs:166:13:166:22 | SSA def(sink37) |
-| Capture.cs:164:37:164:37 | p : String | Capture.cs:166:13:166:22 | SSA def(sink37) |
-| Capture.cs:164:37:164:37 | p : String | Capture.cs:166:13:166:22 | SSA def(sink37) : String |
-| Capture.cs:164:37:164:37 | p : String | Capture.cs:166:13:166:22 | SSA def(sink37) : String |
-| Capture.cs:164:37:164:37 | p : String | Capture.cs:166:22:166:22 | access to parameter p |
-| Capture.cs:164:37:164:37 | p : String | Capture.cs:166:22:166:22 | access to parameter p |
-| Capture.cs:164:37:164:37 | p : String | Capture.cs:166:22:166:22 | access to parameter p : String |
-| Capture.cs:164:37:164:37 | p : String | Capture.cs:166:22:166:22 | access to parameter p : String |
-| Capture.cs:166:13:166:22 | SSA def(sink37) : String | Capture.cs:168:9:168:32 | SSA call def(sink37) |
-| Capture.cs:166:13:166:22 | SSA def(sink37) : String | Capture.cs:168:9:168:32 | SSA call def(sink37) : String |
-| Capture.cs:166:22:166:22 | access to parameter p : String | Capture.cs:166:13:166:22 | SSA def(sink37) |
-| Capture.cs:166:22:166:22 | access to parameter p : String | Capture.cs:166:13:166:22 | SSA def(sink37) |
-| Capture.cs:166:22:166:22 | access to parameter p : String | Capture.cs:166:13:166:22 | SSA def(sink37) : String |
-| Capture.cs:166:22:166:22 | access to parameter p : String | Capture.cs:166:13:166:22 | SSA def(sink37) : String |
-| Capture.cs:168:9:168:23 | this access : Capture | Capture.cs:185:9:185:32 | this access |
-| Capture.cs:168:9:168:23 | this access : Capture | Capture.cs:185:9:185:32 | this access : Capture |
-| Capture.cs:168:9:168:23 | this access : Capture | Capture.cs:194:22:194:23 | this access |
-| Capture.cs:168:9:168:23 | this access : Capture | Capture.cs:194:22:194:23 | this access : Capture |
-| Capture.cs:168:9:168:23 | this access : Capture | Capture.cs:196:20:196:21 | this access |
-| Capture.cs:168:9:168:23 | this access : Capture | Capture.cs:196:20:196:21 | this access : Capture |
-| Capture.cs:168:9:168:32 | SSA call def(sink37) : String | Capture.cs:169:15:169:20 | access to local variable sink37 |
-| Capture.cs:168:9:168:32 | SSA call def(sink37) : String | Capture.cs:169:15:169:20 | access to local variable sink37 : String |
-| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:164:37:164:37 | p |
-| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:164:37:164:37 | p : String |
-| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:168:9:168:32 | SSA call def(sink37) |
-| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:168:9:168:32 | SSA call def(sink37) : String |
-| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:194:25:194:31 | access to parameter tainted |
-| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:194:25:194:31 | access to parameter tainted : String |
-| Capture.cs:171:16:171:28 | SSA def(nonSink0) : String | Capture.cs:176:15:176:22 | access to local variable nonSink0 |
-| Capture.cs:171:16:171:28 | SSA def(nonSink0) : String | Capture.cs:176:15:176:22 | access to local variable nonSink0 : String |
-| Capture.cs:171:16:171:28 | SSA def(nonSink0) : String | Capture.cs:186:15:186:22 | access to local variable nonSink0 |
-| Capture.cs:171:16:171:28 | SSA def(nonSink0) : String | Capture.cs:186:15:186:22 | access to local variable nonSink0 : String |
-| Capture.cs:171:27:171:28 | "" : String | Capture.cs:171:16:171:28 | SSA def(nonSink0) |
-| Capture.cs:171:27:171:28 | "" : String | Capture.cs:171:16:171:28 | SSA def(nonSink0) : String |
-| Capture.cs:171:27:171:28 | "" : String | Capture.cs:176:15:176:22 | access to local variable nonSink0 |
-| Capture.cs:171:27:171:28 | "" : String | Capture.cs:176:15:176:22 | access to local variable nonSink0 : String |
-| Capture.cs:171:27:171:28 | "" : String | Capture.cs:186:15:186:22 | access to local variable nonSink0 |
-| Capture.cs:171:27:171:28 | "" : String | Capture.cs:186:15:186:22 | access to local variable nonSink0 : String |
-| Capture.cs:172:9:175:9 | SSA capture def(tainted) : String | Capture.cs:174:24:174:30 | access to parameter tainted |
-| Capture.cs:172:9:175:9 | SSA capture def(tainted) : String | Capture.cs:174:24:174:30 | access to parameter tainted : String |
-| Capture.cs:176:15:176:22 | access to local variable nonSink0 : String | Capture.cs:186:15:186:22 | access to local variable nonSink0 |
-| Capture.cs:176:15:176:22 | access to local variable nonSink0 : String | Capture.cs:186:15:186:22 | access to local variable nonSink0 : String |
-| Capture.cs:180:13:183:13 | SSA capture def(tainted) : String | Capture.cs:182:28:182:34 | access to parameter tainted |
-| Capture.cs:180:13:183:13 | SSA capture def(tainted) : String | Capture.cs:182:28:182:34 | access to parameter tainted : String |
-| Capture.cs:185:9:185:32 | this access : Capture | Capture.cs:194:22:194:23 | this access |
-| Capture.cs:185:9:185:32 | this access : Capture | Capture.cs:194:22:194:23 | this access : Capture |
-| Capture.cs:185:9:185:32 | this access : Capture | Capture.cs:196:20:196:21 | this access |
-| Capture.cs:185:9:185:32 | this access : Capture | Capture.cs:196:20:196:21 | this access : Capture |
-| Capture.cs:188:26:188:26 | s : String | Capture.cs:191:20:191:22 | [implicit argument] s |
-| Capture.cs:188:26:188:26 | s : String | Capture.cs:191:20:191:22 | [implicit argument] s |
-| Capture.cs:188:26:188:26 | s : String | Capture.cs:191:20:191:22 | [implicit argument] s : String |
-| Capture.cs:188:26:188:26 | s : String | Capture.cs:191:20:191:22 | [implicit argument] s : String |
-| Capture.cs:190:13:190:28 | SSA capture def(s) : String | Capture.cs:190:27:190:27 | access to parameter s |
-| Capture.cs:190:13:190:28 | SSA capture def(s) : String | Capture.cs:190:27:190:27 | access to parameter s |
-| Capture.cs:190:13:190:28 | SSA capture def(s) : String | Capture.cs:190:27:190:27 | access to parameter s : String |
-| Capture.cs:190:13:190:28 | SSA capture def(s) : String | Capture.cs:190:27:190:27 | access to parameter s : String |
-| Capture.cs:190:27:190:27 | access to parameter s : String | Capture.cs:191:20:191:22 | call to local function M |
-| Capture.cs:190:27:190:27 | access to parameter s : String | Capture.cs:191:20:191:22 | call to local function M : String |
-| Capture.cs:191:20:191:22 | [implicit argument] s : String | Capture.cs:190:13:190:28 | SSA capture def(s) |
-| Capture.cs:191:20:191:22 | [implicit argument] s : String | Capture.cs:190:13:190:28 | SSA capture def(s) |
-| Capture.cs:191:20:191:22 | [implicit argument] s : String | Capture.cs:190:13:190:28 | SSA capture def(s) : String |
-| Capture.cs:191:20:191:22 | [implicit argument] s : String | Capture.cs:190:13:190:28 | SSA capture def(s) : String |
-| Capture.cs:191:20:191:22 | [implicit argument] s : String | Capture.cs:191:20:191:22 | call to local function M |
-| Capture.cs:191:20:191:22 | [implicit argument] s : String | Capture.cs:191:20:191:22 | call to local function M |
-| Capture.cs:191:20:191:22 | [implicit argument] s : String | Capture.cs:191:20:191:22 | call to local function M : String |
-| Capture.cs:191:20:191:22 | [implicit argument] s : String | Capture.cs:191:20:191:22 | call to local function M : String |
-| Capture.cs:191:20:191:22 | call to local function M : String | Capture.cs:194:22:194:32 | call to local function Id |
-| Capture.cs:191:20:191:22 | call to local function M : String | Capture.cs:194:22:194:32 | call to local function Id : String |
-| Capture.cs:191:20:191:22 | call to local function M : String | Capture.cs:196:20:196:25 | call to local function Id |
-| Capture.cs:191:20:191:22 | call to local function M : String | Capture.cs:196:20:196:25 | call to local function Id : String |
-| Capture.cs:194:13:194:32 | SSA def(sink38) : String | Capture.cs:195:15:195:20 | access to local variable sink38 |
-| Capture.cs:194:13:194:32 | SSA def(sink38) : String | Capture.cs:195:15:195:20 | access to local variable sink38 : String |
-| Capture.cs:194:22:194:23 | this access : Capture | Capture.cs:196:20:196:21 | this access |
-| Capture.cs:194:22:194:23 | this access : Capture | Capture.cs:196:20:196:21 | this access : Capture |
-| Capture.cs:194:22:194:32 | call to local function Id : String | Capture.cs:194:13:194:32 | SSA def(sink38) |
-| Capture.cs:194:22:194:32 | call to local function Id : String | Capture.cs:194:13:194:32 | SSA def(sink38) : String |
-| Capture.cs:194:22:194:32 | call to local function Id : String | Capture.cs:195:15:195:20 | access to local variable sink38 |
-| Capture.cs:194:22:194:32 | call to local function Id : String | Capture.cs:195:15:195:20 | access to local variable sink38 : String |
-| Capture.cs:194:25:194:31 | access to parameter tainted : String | Capture.cs:188:26:188:26 | s |
-| Capture.cs:194:25:194:31 | access to parameter tainted : String | Capture.cs:188:26:188:26 | s : String |
-| Capture.cs:194:25:194:31 | access to parameter tainted : String | Capture.cs:194:22:194:32 | call to local function Id |
-| Capture.cs:194:25:194:31 | access to parameter tainted : String | Capture.cs:194:22:194:32 | call to local function Id : String |
-| Capture.cs:196:9:196:25 | SSA def(nonSink0) : String | Capture.cs:197:15:197:22 | access to local variable nonSink0 |
-| Capture.cs:196:9:196:25 | SSA def(nonSink0) : String | Capture.cs:197:15:197:22 | access to local variable nonSink0 : String |
-| Capture.cs:196:20:196:25 | call to local function Id : String | Capture.cs:196:9:196:25 | SSA def(nonSink0) |
-| Capture.cs:196:20:196:25 | call to local function Id : String | Capture.cs:196:9:196:25 | SSA def(nonSink0) : String |
-| Capture.cs:196:20:196:25 | call to local function Id : String | Capture.cs:197:15:197:22 | access to local variable nonSink0 |
-| Capture.cs:196:20:196:25 | call to local function Id : String | Capture.cs:197:15:197:22 | access to local variable nonSink0 : String |
-| Capture.cs:196:23:196:24 | "" : String | Capture.cs:188:26:188:26 | s |
-| Capture.cs:196:23:196:24 | "" : String | Capture.cs:188:26:188:26 | s : String |
-| Capture.cs:196:23:196:24 | "" : String | Capture.cs:196:20:196:25 | call to local function Id |
-| Capture.cs:196:23:196:24 | "" : String | Capture.cs:196:20:196:25 | call to local function Id : String |
-| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a |
-| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a |
-| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a |
-| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a |
-| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a |
-| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a : Action |
-| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a : Action |
-| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a : Action |
-| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a : Action |
-| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a : Action |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:64:9:64:18 | this access |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:67:9:67:21 | this access |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:153:21:153:25 | this access |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access |
-| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:31:33:31:47 | access to field SinkField0 |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:31:33:31:47 | access to field SinkField0 : String |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:31:33:31:47 | access to field SinkField0 |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:31:33:31:47 | access to field SinkField0 : String |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:31:33:31:47 | access to field SinkField0 |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:31:33:31:47 | access to field SinkField0 : String |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 |
-| GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 : String |
-| GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) |
-| GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) : String |
-| GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 |
-| GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 : String |
-| GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 |
-| GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 : String |
-| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) |
-| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String |
-| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 |
-| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 : String |
-| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) |
-| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) : String |
-| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 |
-| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 : String |
-| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 |
-| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 : String |
-| GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 : String | GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) |
-| GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 : String | GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) : String |
-| GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 : String | GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 |
-| GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 : String | GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 : String |
-| GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 |
-| GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 : String |
-| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:31:33:31:47 | access to field SinkField0 |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:31:33:31:47 | access to field SinkField0 : String |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 |
-| GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 : String |
-| GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 : String | GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) |
-| GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 : String | GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) : String |
-| GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 |
-| GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 : String |
-| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 |
-| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String |
-| GlobalDataFlow.cs:36:13:36:58 | SSA def(methodInfo) : MethodInfo | GlobalDataFlow.cs:38:9:38:18 | access to local variable methodInfo |
-| GlobalDataFlow.cs:36:13:36:58 | SSA def(methodInfo) : MethodInfo | GlobalDataFlow.cs:38:9:38:18 | access to local variable methodInfo : MethodInfo |
-| GlobalDataFlow.cs:36:26:36:58 | call to method GetMethod : MethodInfo | GlobalDataFlow.cs:36:13:36:58 | SSA def(methodInfo) |
-| GlobalDataFlow.cs:36:26:36:58 | call to method GetMethod : MethodInfo | GlobalDataFlow.cs:36:13:36:58 | SSA def(methodInfo) : MethodInfo |
-| GlobalDataFlow.cs:36:26:36:58 | call to method GetMethod : MethodInfo | GlobalDataFlow.cs:38:9:38:18 | access to local variable methodInfo |
-| GlobalDataFlow.cs:36:26:36:58 | call to method GetMethod : MethodInfo | GlobalDataFlow.cs:38:9:38:18 | access to local variable methodInfo : MethodInfo |
-| GlobalDataFlow.cs:37:13:37:54 | SSA def(args) : Object[] | GlobalDataFlow.cs:38:33:38:36 | access to local variable args |
-| GlobalDataFlow.cs:37:13:37:54 | SSA def(args) : Object[] | GlobalDataFlow.cs:38:33:38:36 | access to local variable args : Object[] |
-| GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) |
-| GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) : Object[] |
-| GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | GlobalDataFlow.cs:38:33:38:36 | access to local variable args |
-| GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | GlobalDataFlow.cs:38:33:38:36 | access to local variable args : Object[] |
-| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:240:26:240:35 | sinkParam1 |
-| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : String |
-| GlobalDataFlow.cs:41:16:41:17 | "" : String | GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 |
-| GlobalDataFlow.cs:41:16:41:17 | "" : String | GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : String |
-| GlobalDataFlow.cs:44:24:44:60 | SSA def(in2) : Action | GlobalDataFlow.cs:45:9:45:11 | access to local variable in2 |
-| GlobalDataFlow.cs:44:24:44:60 | SSA def(in2) : Action | GlobalDataFlow.cs:45:9:45:11 | access to local variable in2 : Action |
-| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 |
-| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 |
-| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 : String |
-| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 : String |
-| GlobalDataFlow.cs:44:30:44:60 | (...) => ... : Action | GlobalDataFlow.cs:44:24:44:60 | SSA def(in2) |
-| GlobalDataFlow.cs:44:30:44:60 | (...) => ... : Action | GlobalDataFlow.cs:44:24:44:60 | SSA def(in2) : Action |
-| GlobalDataFlow.cs:44:30:44:60 | (...) => ... : Action | GlobalDataFlow.cs:45:9:45:11 | access to local variable in2 |
-| GlobalDataFlow.cs:44:30:44:60 | (...) => ... : Action | GlobalDataFlow.cs:45:9:45:11 | access to local variable in2 : Action |
-| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:44:30:44:39 | sinkParam2 |
-| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String |
-| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 |
-| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String |
-| GlobalDataFlow.cs:48:24:48:69 | SSA def(nonIn1) : Action | GlobalDataFlow.cs:49:9:49:14 | access to local variable nonIn1 |
-| GlobalDataFlow.cs:48:24:48:69 | SSA def(nonIn1) : Action | GlobalDataFlow.cs:49:9:49:14 | access to local variable nonIn1 : Action |
-| GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 : String | GlobalDataFlow.cs:48:56:48:68 | access to parameter nonSinkParam1 |
-| GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 : String | GlobalDataFlow.cs:48:56:48:68 | access to parameter nonSinkParam1 |
-| GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 : String | GlobalDataFlow.cs:48:56:48:68 | access to parameter nonSinkParam1 : String |
-| GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 : String | GlobalDataFlow.cs:48:56:48:68 | access to parameter nonSinkParam1 : String |
-| GlobalDataFlow.cs:48:33:48:69 | (...) => ... : Action