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 | GlobalDataFlow.cs:48:24:48:69 | SSA def(nonIn1) | -| GlobalDataFlow.cs:48:33:48:69 | (...) => ... : Action | GlobalDataFlow.cs:48:24:48:69 | SSA def(nonIn1) : Action | -| GlobalDataFlow.cs:48:33:48:69 | (...) => ... : Action | GlobalDataFlow.cs:49:9:49:14 | access to local variable nonIn1 | -| GlobalDataFlow.cs:48:33:48:69 | (...) => ... : Action | GlobalDataFlow.cs:49:9:49:14 | access to local variable nonIn1 : Action | -| GlobalDataFlow.cs:49:16:49:17 | "" : String | GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 | -| GlobalDataFlow.cs:49:16:49:17 | "" : String | GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 : String | -| GlobalDataFlow.cs:52:15:52:17 | delegate creation of type Action : Action | GlobalDataFlow.cs:359:36:359:36 | a | -| GlobalDataFlow.cs:52:15:52:17 | delegate creation of type Action : Action | GlobalDataFlow.cs:359:36:359:36 | a : Action | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:359:41:359:41 | x | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:359:41:359:41 | x : String | -| GlobalDataFlow.cs:53:15:53:15 | x : String | GlobalDataFlow.cs:53:24:53:24 | access to parameter x | -| GlobalDataFlow.cs:53:15:53:15 | x : String | GlobalDataFlow.cs:53:24:53:24 | access to parameter x | -| GlobalDataFlow.cs:53:15:53:15 | x : String | GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | -| GlobalDataFlow.cs:53:15:53:15 | x : String | GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | -| GlobalDataFlow.cs:53:15:53:15 | x : T | GlobalDataFlow.cs:53:24:53:24 | access to parameter x | -| GlobalDataFlow.cs:53:15:53:15 | x : T | GlobalDataFlow.cs:53:24:53:24 | access to parameter x : T | -| GlobalDataFlow.cs:53:15:53:25 | (...) => ... : Action | GlobalDataFlow.cs:359:36:359:36 | a | -| GlobalDataFlow.cs:53:15:53:25 | (...) => ... : Action | GlobalDataFlow.cs:359:36:359:36 | a : Action | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : T | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : T | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : T | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:359:41:359:41 | x | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:359:41:359:41 | x : String | -| GlobalDataFlow.cs:54:23:54:41 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a | -| GlobalDataFlow.cs:54:23:54:41 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:373:52:373:52 | x | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:373:52:373:52 | x : String | -| GlobalDataFlow.cs:55:23:55:25 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a | -| GlobalDataFlow.cs:55:23:55:25 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:373:52:373:52 | x | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:373:52:373:52 | x : String | -| GlobalDataFlow.cs:56:9:56:48 | SSA def(DataFlow.myDelegate) : MyDelegate | GlobalDataFlow.cs:57:23:57:32 | access to field myDelegate | -| GlobalDataFlow.cs:56:9:56:48 | SSA def(DataFlow.myDelegate) : MyDelegate | GlobalDataFlow.cs:57:23:57:32 | access to field myDelegate : MyDelegate | -| GlobalDataFlow.cs:56:22:56:48 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:56:9:56:48 | SSA def(DataFlow.myDelegate) | -| GlobalDataFlow.cs:56:22:56:48 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:56:9:56:48 | SSA def(DataFlow.myDelegate) : MyDelegate | -| GlobalDataFlow.cs:56:22:56:48 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:57:23:57:32 | access to field myDelegate | -| GlobalDataFlow.cs:56:22:56:48 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:57:23:57:32 | access to field myDelegate : MyDelegate | -| GlobalDataFlow.cs:56:37:56:37 | x : String | GlobalDataFlow.cs:56:46:56:46 | access to parameter x | -| GlobalDataFlow.cs:56:37:56:37 | x : String | GlobalDataFlow.cs:56:46:56:46 | access to parameter x | -| GlobalDataFlow.cs:56:37:56:37 | x : String | GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | -| GlobalDataFlow.cs:56:37:56:37 | x : String | GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | GlobalDataFlow.cs:265:26:265:35 | sinkParam7 | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | GlobalDataFlow.cs:265:26:265:35 | sinkParam7 | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | -| GlobalDataFlow.cs:57:23:57:32 | access to field myDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a | -| GlobalDataFlow.cs:57:23:57:32 | access to field myDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:373:52:373:52 | x | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:373:52:373:52 | x : String | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : String | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : String | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : String | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 : String | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : String | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 : String | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : T | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : T | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 : T | -| GlobalDataFlow.cs:60:15:60:51 | (...) => ... : Action | GlobalDataFlow.cs:359:36:359:36 | a | -| GlobalDataFlow.cs:60:15:60:51 | (...) => ... : Action | GlobalDataFlow.cs:359:36:359:36 | a : Action | -| GlobalDataFlow.cs:60:54:60:66 | "not tainted" : String | GlobalDataFlow.cs:359:41:359:41 | x | -| GlobalDataFlow.cs:60:54:60:66 | "not tainted" : String | GlobalDataFlow.cs:359:41:359:41 | x : String | -| GlobalDataFlow.cs:61:23:61:75 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a | -| GlobalDataFlow.cs:61:23:61:75 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | -| GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | GlobalDataFlow.cs:61:61:61:73 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | GlobalDataFlow.cs:61:61:61:73 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | GlobalDataFlow.cs:61:61:61:73 | access to parameter nonSinkParam0 : String | -| GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | GlobalDataFlow.cs:61:61:61:73 | access to parameter nonSinkParam0 : String | -| GlobalDataFlow.cs:61:78:61:90 | "not tainted" : String | GlobalDataFlow.cs:373:52:373:52 | x | -| GlobalDataFlow.cs:61:78:61:90 | "not tainted" : String | GlobalDataFlow.cs:373:52:373:52 | x : String | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:67:9:67:21 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:153:21:153:25 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:404:9:404:11 | this | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:404:9:404:11 | this : DataFlow | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:404:9:404:11 | value | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:404:9:404:11 | value : String | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:153:21:153:25 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:410:9:410:11 | this | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:410:9:410:11 | this : DataFlow | -| GlobalDataFlow.cs:67:25:67:37 | "not tainted" : String | GlobalDataFlow.cs:410:9:410:11 | value | -| GlobalDataFlow.cs:67:25:67:37 | "not tainted" : String | GlobalDataFlow.cs:410:9:410:11 | value : String | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : String | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : T | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : T | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : T | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : T | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : T | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : String | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : String | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : T | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : T | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:21:70:46 | call to method Return | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : T | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : T | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : Object | GlobalDataFlow.cs:72:21:72:101 | (...) ... | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : Object | GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | GlobalDataFlow.cs:72:21:72:101 | (...) ... | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : T | GlobalDataFlow.cs:72:21:72:101 | (...) ... | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : T | GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : T | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | GlobalDataFlow.cs:275:26:275:26 | x : T | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : String | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : T | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : Object | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:281:32:281:32 | x : Object | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : String | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:281:32:281:32 | x : String | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : T | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : T | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:281:32:281:32 | x : T | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : Object | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : Object | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : Object | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : Object | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : Object | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : Object | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : String | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : T | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : T | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : T | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : T | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : T | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : T | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : Object | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : Object | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : Object | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : String | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : String | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : T | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : T | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : T | -| GlobalDataFlow.cs:77:13:77:22 | SSA def(sink3) : String | GlobalDataFlow.cs:78:30:78:34 | access to local variable sink3 | -| GlobalDataFlow.cs:77:13:77:22 | SSA def(sink3) : String | GlobalDataFlow.cs:78:30:78:34 | access to local variable sink3 : String | -| GlobalDataFlow.cs:77:13:77:22 | SSA def(sink3) : String | GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 | -| GlobalDataFlow.cs:77:13:77:22 | SSA def(sink3) : String | GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 : String | -| GlobalDataFlow.cs:77:21:77:22 | "" : String | GlobalDataFlow.cs:77:13:77:22 | SSA def(sink3) | -| GlobalDataFlow.cs:77:21:77:22 | "" : String | GlobalDataFlow.cs:77:13:77:22 | SSA def(sink3) : String | -| GlobalDataFlow.cs:77:21:77:22 | "" : String | GlobalDataFlow.cs:78:30:78:34 | access to local variable sink3 | -| GlobalDataFlow.cs:77:21:77:22 | "" : String | GlobalDataFlow.cs:78:30:78:34 | access to local variable sink3 : String | -| GlobalDataFlow.cs:77:21:77:22 | "" : String | GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 | -| GlobalDataFlow.cs:77:21:77:22 | "" : String | GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 : String | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : Object | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : Object | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : Object | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : Object | GlobalDataFlow.cs:287:32:287:32 | x : Object | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | GlobalDataFlow.cs:287:32:287:32 | x : String | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : T | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : T | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : T | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : T | GlobalDataFlow.cs:287:32:287:32 | x : T | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | -| GlobalDataFlow.cs:78:30:78:34 | access to local variable sink3 : String | GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | access to local variable sink3 : String | GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 : String | -| GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 : String | GlobalDataFlow.cs:287:50:287:50 | z | -| GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 : String | GlobalDataFlow.cs:287:50:287:50 | z : String | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable | GlobalDataFlow.cs:426:71:426:71 | e | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable | GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | GlobalDataFlow.cs:426:71:426:71 | e | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | GlobalDataFlow.cs:426:71:426:71 | e : String[] | -| GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | GlobalDataFlow.cs:80:23:80:65 | (...) ... | -| GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | -| GlobalDataFlow.cs:80:79:80:79 | x : String | GlobalDataFlow.cs:80:84:80:84 | access to parameter x | -| GlobalDataFlow.cs:80:79:80:79 | x : String | GlobalDataFlow.cs:80:84:80:84 | access to parameter x : String | -| GlobalDataFlow.cs:80:79:80:79 | x : T | GlobalDataFlow.cs:80:84:80:84 | access to parameter x | -| GlobalDataFlow.cs:80:79:80:79 | x : T | GlobalDataFlow.cs:80:84:80:84 | access to parameter x : T | -| GlobalDataFlow.cs:80:79:80:84 | (...) => ... : Func | GlobalDataFlow.cs:426:85:426:85 | f | -| GlobalDataFlow.cs:80:79:80:84 | (...) => ... : Func | GlobalDataFlow.cs:426:85:426:85 | f : Func | -| GlobalDataFlow.cs:80:84:80:84 | access to parameter x : String | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:80:84:80:84 | access to parameter x : String | GlobalDataFlow.cs:431:44:431:47 | delegate call : String | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : IEnumerable | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | -| GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | GlobalDataFlow.cs:82:23:82:74 | (...) ... | -| GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable | GlobalDataFlow.cs:84:126:84:126 | x | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable | GlobalDataFlow.cs:84:126:84:126 | x : IEnumerable | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | GlobalDataFlow.cs:84:126:84:126 | x | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | GlobalDataFlow.cs:84:126:84:126 | x : String[] | -| GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | GlobalDataFlow.cs:84:23:84:74 | (...) ... | -| GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:84:103:84:121 | array creation of type String[] : String[] | GlobalDataFlow.cs:84:82:84:121 | (...) ... | -| GlobalDataFlow.cs:84:103:84:121 | array creation of type String[] : String[] | GlobalDataFlow.cs:84:82:84:121 | (...) ... : String[] | -| GlobalDataFlow.cs:84:126:84:126 | x : String | GlobalDataFlow.cs:84:135:84:135 | access to parameter x | -| GlobalDataFlow.cs:84:126:84:126 | x : String | GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | -| GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... | -| GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:86:13:86:136 | SSA def(sink16) : IEnumerable | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | -| GlobalDataFlow.cs:86:13:86:136 | SSA def(sink16) : IEnumerable | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 : IEnumerable | -| GlobalDataFlow.cs:86:22:86:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:13:86:136 | SSA def(sink16) | -| GlobalDataFlow.cs:86:22:86:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:13:86:136 | SSA def(sink16) : IEnumerable | -| GlobalDataFlow.cs:86:22:86:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | -| GlobalDataFlow.cs:86:22:86:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 : IEnumerable | -| GlobalDataFlow.cs:86:44:86:62 | array creation of type String[] : String[] | GlobalDataFlow.cs:86:23:86:62 | (...) ... | -| GlobalDataFlow.cs:86:44:86:62 | array creation of type String[] : String[] | GlobalDataFlow.cs:86:23:86:62 | (...) ... : String[] | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable | GlobalDataFlow.cs:86:129:86:129 | y | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable | GlobalDataFlow.cs:86:129:86:129 | y : IEnumerable | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | GlobalDataFlow.cs:86:129:86:129 | y | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | GlobalDataFlow.cs:86:129:86:129 | y : String[] | -| GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] | GlobalDataFlow.cs:86:70:86:121 | (...) ... | -| GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:86:129:86:129 | y : String | GlobalDataFlow.cs:86:135:86:135 | access to parameter y | -| GlobalDataFlow.cs:86:129:86:129 | y : String | GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String | -| GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... | -| GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:13:88:70 | SSA def(sink17) : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | -| GlobalDataFlow.cs:88:13:88:70 | SSA def(sink17) : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 : String | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:49:88:49 | s | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:49:88:49 | s : IEnumerable | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:88:22:88:70 | call to method Aggregate : String | GlobalDataFlow.cs:88:13:88:70 | SSA def(sink17) | -| GlobalDataFlow.cs:88:22:88:70 | call to method Aggregate : String | GlobalDataFlow.cs:88:13:88:70 | SSA def(sink17) : String | -| GlobalDataFlow.cs:88:22:88:70 | call to method Aggregate : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | -| GlobalDataFlow.cs:88:22:88:70 | call to method Aggregate : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 : String | -| GlobalDataFlow.cs:88:39:88:40 | "" : String | GlobalDataFlow.cs:88:44:88:46 | acc | -| GlobalDataFlow.cs:88:39:88:40 | "" : String | GlobalDataFlow.cs:88:44:88:46 | acc : String | -| GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | GlobalDataFlow.cs:88:64:88:64 | x | -| GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | GlobalDataFlow.cs:88:64:88:64 | x : String | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:57 | access to parameter acc | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:57 | access to parameter acc : String | -| GlobalDataFlow.cs:88:49:88:49 | s : String | GlobalDataFlow.cs:88:61:88:61 | access to parameter s | -| GlobalDataFlow.cs:88:49:88:49 | s : String | GlobalDataFlow.cs:88:61:88:61 | access to parameter s : String | -| GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... | -| GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:64:88:64 | x : String | GlobalDataFlow.cs:88:69:88:69 | access to parameter x | -| GlobalDataFlow.cs:88:64:88:64 | x : String | GlobalDataFlow.cs:88:69:88:69 | access to parameter x : String | -| GlobalDataFlow.cs:88:69:88:69 | access to parameter x : String | GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... | -| GlobalDataFlow.cs:88:69:88:69 | access to parameter x : String | GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:23:90:62 | (...) ... : IEnumerable | GlobalDataFlow.cs:90:97:90:97 | s | -| GlobalDataFlow.cs:90:23:90:62 | (...) ... : IEnumerable | GlobalDataFlow.cs:90:97:90:97 | s : IEnumerable | -| GlobalDataFlow.cs:90:23:90:62 | (...) ... : String[] | GlobalDataFlow.cs:90:97:90:97 | s | -| GlobalDataFlow.cs:90:23:90:62 | (...) ... : String[] | GlobalDataFlow.cs:90:97:90:97 | s : String[] | -| GlobalDataFlow.cs:90:44:90:62 | array creation of type String[] : String[] | GlobalDataFlow.cs:90:23:90:62 | (...) ... | -| GlobalDataFlow.cs:90:44:90:62 | array creation of type String[] : String[] | GlobalDataFlow.cs:90:23:90:62 | (...) ... : String[] | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:90:75:90:88 | call to method First : String | GlobalDataFlow.cs:90:92:90:94 | acc | -| GlobalDataFlow.cs:90:75:90:88 | call to method First : String | GlobalDataFlow.cs:90:92:90:94 | acc : String | -| GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:90:112:90:112 | x | -| GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:90:112:90:112 | x : String | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:105 | access to parameter acc | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:105 | access to parameter acc : String | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:109:90:109 | access to parameter s | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | -| GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... | -| GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:112:90:112 | x : String | GlobalDataFlow.cs:90:117:90:117 | access to parameter x | -| GlobalDataFlow.cs:90:112:90:112 | x : String | GlobalDataFlow.cs:90:117:90:117 | access to parameter x : String | -| GlobalDataFlow.cs:90:117:90:117 | access to parameter x : String | GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... | -| GlobalDataFlow.cs:90:117:90:117 | access to parameter x : String | GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | -| GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) : Int32 | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | -| GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) : Int32 | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 : Int32 | -| GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) : Boolean | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | -| GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) : Boolean | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 : Boolean | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : T | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : T | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : T | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : T | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:100:31:100:32 | "" : String | GlobalDataFlow.cs:100:24:100:33 | call to method Return | -| GlobalDataFlow.cs:100:31:100:32 | "" : String | GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | -| GlobalDataFlow.cs:100:31:100:32 | "" : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:100:31:100:32 | "" : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 | -| GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 | -| GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : Object | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : Object | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 : Object | -| GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : String | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : String | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : T | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : T | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : Object | GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : Object | GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : Object | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : Object | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : Object | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 : Object | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : String | GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : String | GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : String | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : String | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : T | GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : T | GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : T | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : T | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : Object | GlobalDataFlow.cs:102:20:102:103 | (...) ... | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : Object | GlobalDataFlow.cs:102:20:102:103 | (...) ... : Object | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : String | GlobalDataFlow.cs:102:20:102:103 | (...) ... | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : String | GlobalDataFlow.cs:102:20:102:103 | (...) ... : String | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : T | GlobalDataFlow.cs:102:20:102:103 | (...) ... | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : T | GlobalDataFlow.cs:102:20:102:103 | (...) ... : T | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : String | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : T | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | GlobalDataFlow.cs:275:26:275:26 | x : T | -| GlobalDataFlow.cs:104:19:104:20 | "" : String | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:104:19:104:20 | "" : String | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:104:19:104:20 | "" : String | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:104:19:104:20 | "" : String | GlobalDataFlow.cs:281:32:281:32 | x : String | -| GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:105:15:105:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:105:15:105:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:105:15:105:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:105:15:105:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:281:32:281:32 | x : Object | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : String | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | GlobalDataFlow.cs:281:32:281:32 | x : String | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : T | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | GlobalDataFlow.cs:281:32:281:32 | x : T | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : String | GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : String | GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : String | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : String | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : String | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : String | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:19:108:20 | "" : String | GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:108:19:108:20 | "" : String | GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:108:19:108:20 | "" : String | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:108:19:108:20 | "" : String | GlobalDataFlow.cs:287:32:287:32 | x : String | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : String | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : String | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : T | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : T | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:287:50:287:50 | z | -| GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:287:50:287:50 | z : String | -| GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:287:50:287:50 | z | -| GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:287:50:287:50 | z : T | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : Object | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:287:32:287:32 | x : Object | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : String | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : String | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | GlobalDataFlow.cs:287:32:287:32 | x : String | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : T | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : T | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | GlobalDataFlow.cs:287:32:287:32 | x : T | -| GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : Object | GlobalDataFlow.cs:124:39:124:43 | access to local variable sink1 | -| GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : Object | GlobalDataFlow.cs:124:39:124:43 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : String | GlobalDataFlow.cs:124:39:124:43 | access to local variable sink1 | -| GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : String | GlobalDataFlow.cs:124:39:124:43 | access to local variable sink1 : String | -| GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : T | GlobalDataFlow.cs:124:39:124:43 | access to local variable sink1 | -| GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : T | GlobalDataFlow.cs:124:39:124:43 | access to local variable sink1 : T | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:287:50:287:50 | z | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:287:50:287:50 | z : String | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:287:50:287:50 | z | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:287:50:287:50 | z : T | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable | GlobalDataFlow.cs:426:71:426:71 | e | -| GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable | GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | -| GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | GlobalDataFlow.cs:426:71:426:71 | e | -| GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | GlobalDataFlow.cs:426:71:426:71 | e : String[] | -| GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | GlobalDataFlow.cs:112:25:112:70 | (...) ... | -| GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:112:84:112:84 | x : String | GlobalDataFlow.cs:112:89:112:89 | access to parameter x | -| GlobalDataFlow.cs:112:84:112:84 | x : String | GlobalDataFlow.cs:112:89:112:89 | access to parameter x : String | -| GlobalDataFlow.cs:112:84:112:84 | x : T | GlobalDataFlow.cs:112:89:112:89 | access to parameter x | -| GlobalDataFlow.cs:112:84:112:84 | x : T | GlobalDataFlow.cs:112:89:112:89 | access to parameter x : T | -| GlobalDataFlow.cs:112:84:112:89 | (...) => ... : Func | GlobalDataFlow.cs:426:85:426:85 | f | -| GlobalDataFlow.cs:112:84:112:89 | (...) => ... : Func | GlobalDataFlow.cs:426:85:426:85 | f : Func | -| GlobalDataFlow.cs:112:89:112:89 | access to parameter x : String | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:112:89:112:89 | access to parameter x : String | GlobalDataFlow.cs:431:44:431:47 | delegate call : String | -| GlobalDataFlow.cs:114:9:114:82 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:115:15:115:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:114:9:114:82 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:115:15:115:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:114:20:114:82 | call to method Select : IEnumerable | GlobalDataFlow.cs:114:9:114:82 | SSA def(nonSink1) | -| GlobalDataFlow.cs:114:20:114:82 | call to method Select : IEnumerable | GlobalDataFlow.cs:114:9:114:82 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:114:20:114:82 | call to method Select : IEnumerable | GlobalDataFlow.cs:115:15:115:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:114:20:114:82 | call to method Select : IEnumerable | GlobalDataFlow.cs:115:15:115:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable | GlobalDataFlow.cs:114:76:114:76 | x | -| GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable | GlobalDataFlow.cs:114:76:114:76 | x : IEnumerable | -| GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | GlobalDataFlow.cs:114:76:114:76 | x | -| GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | GlobalDataFlow.cs:114:76:114:76 | x : String[] | -| GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:114:76:114:76 | x : String | GlobalDataFlow.cs:114:81:114:81 | access to parameter x | -| GlobalDataFlow.cs:114:76:114:76 | x : String | GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String | -| GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String | GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... | -| GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String | GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... : String | -| GlobalDataFlow.cs:116:9:116:134 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:117:15:117:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:116:9:116:134 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:117:15:117:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:116:20:116:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:116:9:116:134 | SSA def(nonSink1) | -| GlobalDataFlow.cs:116:20:116:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:116:9:116:134 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:116:20:116:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:117:15:117:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:116:20:116:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:117:15:117:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | GlobalDataFlow.cs:116:21:116:72 | (...) ... | -| GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:116:80:116:119 | (...) ... : IEnumerable | GlobalDataFlow.cs:116:127:116:127 | y | -| GlobalDataFlow.cs:116:80:116:119 | (...) ... : IEnumerable | GlobalDataFlow.cs:116:127:116:127 | y : IEnumerable | -| GlobalDataFlow.cs:116:80:116:119 | (...) ... : String[] | GlobalDataFlow.cs:116:127:116:127 | y | -| GlobalDataFlow.cs:116:80:116:119 | (...) ... : String[] | GlobalDataFlow.cs:116:127:116:127 | y : String[] | -| GlobalDataFlow.cs:116:101:116:119 | array creation of type String[] : String[] | GlobalDataFlow.cs:116:80:116:119 | (...) ... | -| GlobalDataFlow.cs:116:101:116:119 | array creation of type String[] : String[] | GlobalDataFlow.cs:116:80:116:119 | (...) ... : String[] | -| GlobalDataFlow.cs:116:127:116:127 | y : String | GlobalDataFlow.cs:116:133:116:133 | access to parameter y | -| GlobalDataFlow.cs:116:127:116:127 | y : String | GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String | -| GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String | GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... | -| GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String | GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... : String | -| GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 | -| GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:118:21:118:60 | (...) ... : IEnumerable | GlobalDataFlow.cs:118:124:118:124 | x | -| GlobalDataFlow.cs:118:21:118:60 | (...) ... : IEnumerable | GlobalDataFlow.cs:118:124:118:124 | x : IEnumerable | -| GlobalDataFlow.cs:118:21:118:60 | (...) ... : String[] | GlobalDataFlow.cs:118:124:118:124 | x | -| GlobalDataFlow.cs:118:21:118:60 | (...) ... : String[] | GlobalDataFlow.cs:118:124:118:124 | x : String[] | -| GlobalDataFlow.cs:118:42:118:60 | array creation of type String[] : String[] | GlobalDataFlow.cs:118:21:118:60 | (...) ... | -| GlobalDataFlow.cs:118:42:118:60 | array creation of type String[] : String[] | GlobalDataFlow.cs:118:21:118:60 | (...) ... : String[] | -| GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | GlobalDataFlow.cs:118:68:118:119 | (...) ... | -| GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] | -| GlobalDataFlow.cs:118:124:118:124 | x : String | GlobalDataFlow.cs:118:133:118:133 | access to parameter x | -| GlobalDataFlow.cs:118:124:118:124 | x : String | GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String | -| GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String | GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... | -| GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String | GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | -| GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 : IEnumerable | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 | -| GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 : IEnumerable | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:120:9:120:64 | SSA def(nonSink0) : String | GlobalDataFlow.cs:121:15:121:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:120:9:120:64 | SSA def(nonSink0) : String | GlobalDataFlow.cs:121:15:121:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:120:20:120:64 | call to method Aggregate : String | GlobalDataFlow.cs:120:9:120:64 | SSA def(nonSink0) | -| GlobalDataFlow.cs:120:20:120:64 | call to method Aggregate : String | GlobalDataFlow.cs:120:9:120:64 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:120:20:120:64 | call to method Aggregate : String | GlobalDataFlow.cs:121:15:121:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:120:20:120:64 | call to method Aggregate : String | GlobalDataFlow.cs:121:15:121:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:120:37:120:38 | "" : String | GlobalDataFlow.cs:120:42:120:44 | acc | -| GlobalDataFlow.cs:120:37:120:38 | "" : String | GlobalDataFlow.cs:120:42:120:44 | acc : String | -| GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... : String | GlobalDataFlow.cs:120:58:120:58 | x | -| GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... : String | GlobalDataFlow.cs:120:58:120:58 | x : String | -| GlobalDataFlow.cs:120:42:120:44 | acc : String | GlobalDataFlow.cs:120:53:120:55 | access to parameter acc | -| GlobalDataFlow.cs:120:42:120:44 | acc : String | GlobalDataFlow.cs:120:53:120:55 | access to parameter acc : String | -| GlobalDataFlow.cs:120:53:120:55 | access to parameter acc : String | GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... | -| GlobalDataFlow.cs:120:53:120:55 | access to parameter acc : String | GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... : String | -| GlobalDataFlow.cs:120:58:120:58 | x : String | GlobalDataFlow.cs:120:63:120:63 | access to parameter x | -| GlobalDataFlow.cs:120:58:120:58 | x : String | GlobalDataFlow.cs:120:63:120:63 | access to parameter x : String | -| GlobalDataFlow.cs:120:63:120:63 | access to parameter x : String | GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... | -| GlobalDataFlow.cs:120:63:120:63 | access to parameter x : String | GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... : String | -| GlobalDataFlow.cs:122:9:122:69 | SSA def(nonSink0) : String | GlobalDataFlow.cs:123:15:123:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:122:9:122:69 | SSA def(nonSink0) : String | GlobalDataFlow.cs:123:15:123:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:47:122:47 | s | -| GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:47:122:47 | s : IEnumerable | -| GlobalDataFlow.cs:122:20:122:69 | call to method Aggregate : String | GlobalDataFlow.cs:122:9:122:69 | SSA def(nonSink0) | -| GlobalDataFlow.cs:122:20:122:69 | call to method Aggregate : String | GlobalDataFlow.cs:122:9:122:69 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:122:20:122:69 | call to method Aggregate : String | GlobalDataFlow.cs:123:15:123:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:122:20:122:69 | call to method Aggregate : String | GlobalDataFlow.cs:123:15:123:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:122:37:122:38 | "" : String | GlobalDataFlow.cs:122:42:122:44 | acc | -| GlobalDataFlow.cs:122:37:122:38 | "" : String | GlobalDataFlow.cs:122:42:122:44 | acc : String | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:55 | access to parameter acc | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:55 | access to parameter acc : String | -| GlobalDataFlow.cs:122:47:122:47 | s : String | GlobalDataFlow.cs:122:59:122:59 | access to parameter s | -| GlobalDataFlow.cs:122:47:122:47 | s : String | GlobalDataFlow.cs:122:59:122:59 | access to parameter s : String | -| GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | GlobalDataFlow.cs:122:41:122:59 | [output] (...) => ... | -| GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | GlobalDataFlow.cs:122:41:122:59 | [output] (...) => ... : String | -| GlobalDataFlow.cs:122:67:122:68 | "" : String | GlobalDataFlow.cs:122:62:122:68 | [output] (...) => ... | -| GlobalDataFlow.cs:122:67:122:68 | "" : String | GlobalDataFlow.cs:122:62:122:68 | [output] (...) => ... : String | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | GlobalDataFlow.cs:124:52:124:52 | s | -| GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | GlobalDataFlow.cs:124:52:124:52 | s : IEnumerable | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... : String | GlobalDataFlow.cs:124:61:124:61 | x | -| GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... : String | GlobalDataFlow.cs:124:61:124:61 | x : String | -| GlobalDataFlow.cs:124:52:124:52 | s : String | GlobalDataFlow.cs:124:58:124:58 | access to parameter s | -| GlobalDataFlow.cs:124:52:124:52 | s : String | GlobalDataFlow.cs:124:58:124:58 | access to parameter s : String | -| GlobalDataFlow.cs:124:58:124:58 | access to parameter s : String | GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... | -| GlobalDataFlow.cs:124:58:124:58 | access to parameter s : String | GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... : String | -| GlobalDataFlow.cs:124:61:124:61 | x : String | GlobalDataFlow.cs:124:66:124:66 | access to parameter x | -| GlobalDataFlow.cs:124:61:124:61 | x : String | GlobalDataFlow.cs:124:66:124:66 | access to parameter x : String | -| GlobalDataFlow.cs:124:66:124:66 | access to parameter x : String | GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... | -| GlobalDataFlow.cs:124:66:124:66 | access to parameter x : String | GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) : Int32 | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 | -| GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) : Int32 | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 : Int32 | -| GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 | -| GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) : Boolean | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 | -| GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) : Boolean | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 : Boolean | -| GlobalDataFlow.cs:134:30:134:64 | SSA def(return) : Func | GlobalDataFlow.cs:135:21:135:27 | access to local variable return | -| GlobalDataFlow.cs:134:30:134:64 | SSA def(return) : Func | GlobalDataFlow.cs:135:21:135:27 | access to local variable return : Func | -| GlobalDataFlow.cs:134:30:134:64 | SSA def(return) : Func | GlobalDataFlow.cs:139:20:139:26 | access to local variable return | -| GlobalDataFlow.cs:134:30:134:64 | SSA def(return) : Func | GlobalDataFlow.cs:139:20:139:26 | access to local variable return : Func | -| GlobalDataFlow.cs:134:40:134:40 | x : Object | GlobalDataFlow.cs:134:63:134:63 | access to parameter x | -| GlobalDataFlow.cs:134:40:134:40 | x : Object | GlobalDataFlow.cs:134:63:134:63 | access to parameter x : Object | -| GlobalDataFlow.cs:134:40:134:40 | x : String | GlobalDataFlow.cs:134:63:134:63 | access to parameter x | -| GlobalDataFlow.cs:134:40:134:40 | x : String | GlobalDataFlow.cs:134:63:134:63 | access to parameter x | -| GlobalDataFlow.cs:134:40:134:40 | x : String | GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | -| GlobalDataFlow.cs:134:40:134:40 | x : String | GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | -| GlobalDataFlow.cs:134:40:134:40 | x : T | GlobalDataFlow.cs:134:63:134:63 | access to parameter x | -| GlobalDataFlow.cs:134:40:134:40 | x : T | GlobalDataFlow.cs:134:63:134:63 | access to parameter x : T | -| GlobalDataFlow.cs:134:40:134:64 | (...) => ... : Func | GlobalDataFlow.cs:134:30:134:64 | SSA def(return) | -| GlobalDataFlow.cs:134:40:134:64 | (...) => ... : Func | GlobalDataFlow.cs:134:30:134:64 | SSA def(return) : Func | -| GlobalDataFlow.cs:134:40:134:64 | (...) => ... : Func | GlobalDataFlow.cs:135:21:135:27 | access to local variable return | -| GlobalDataFlow.cs:134:40:134:64 | (...) => ... : Func | GlobalDataFlow.cs:135:21:135:27 | access to local variable return : Func | -| GlobalDataFlow.cs:134:40:134:64 | (...) => ... : Func | GlobalDataFlow.cs:139:20:139:26 | access to local variable return | -| GlobalDataFlow.cs:134:40:134:64 | (...) => ... : Func | GlobalDataFlow.cs:139:20:139:26 | access to local variable return : Func | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : String | GlobalDataFlow.cs:135:21:135:34 | delegate call | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : String | GlobalDataFlow.cs:135:21:135:34 | delegate call : String | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : String | GlobalDataFlow.cs:139:20:139:36 | delegate call | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : String | GlobalDataFlow.cs:139:20:139:36 | delegate call : String | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | GlobalDataFlow.cs:135:21:135:34 | delegate call | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | GlobalDataFlow.cs:135:21:135:34 | delegate call : T | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | GlobalDataFlow.cs:139:20:139:36 | delegate call | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | GlobalDataFlow.cs:139:20:139:36 | delegate call : T | -| GlobalDataFlow.cs:134:55:134:60 | delegate creation of type Func : Func | GlobalDataFlow.cs:364:41:364:41 | f | -| GlobalDataFlow.cs:134:55:134:60 | delegate creation of type Func : Func | GlobalDataFlow.cs:364:41:364:41 | f : Func | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : Object | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : Object | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : Object | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : Object | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : Object | GlobalDataFlow.cs:364:46:364:46 | x : Object | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:364:46:364:46 | x : String | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:364:46:364:46 | x : String | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : T | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : T | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : T | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : T | GlobalDataFlow.cs:364:46:364:46 | x : T | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : Object | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : Object | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : Object | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : Object | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : Object | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : String | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : T | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : T | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : T | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : T | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : T | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | -| GlobalDataFlow.cs:135:21:135:27 | access to local variable return : Func | GlobalDataFlow.cs:139:20:139:26 | access to local variable return | -| GlobalDataFlow.cs:135:21:135:27 | access to local variable return : Func | GlobalDataFlow.cs:139:20:139:26 | access to local variable return : Func | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : Object | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : Object | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : String | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : String | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : T | GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : T | GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : T | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : T | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : T | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : T | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : T | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : T | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | GlobalDataFlow.cs:134:40:134:40 | x | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | GlobalDataFlow.cs:134:40:134:40 | x : Object | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:21:135:34 | delegate call | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | GlobalDataFlow.cs:134:40:134:40 | x | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | GlobalDataFlow.cs:134:40:134:40 | x : String | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | GlobalDataFlow.cs:135:21:135:34 | delegate call | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | GlobalDataFlow.cs:135:21:135:34 | delegate call : String | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | GlobalDataFlow.cs:134:40:134:40 | x | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | GlobalDataFlow.cs:134:40:134:40 | x : T | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | GlobalDataFlow.cs:135:21:135:34 | delegate call | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | GlobalDataFlow.cs:135:21:135:34 | delegate call : T | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : Object | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : Object | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : T | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : T | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | -| GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) : String | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) : String | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) : T | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) : T | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : String | GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : String | GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : String | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : String | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : T | GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : T | GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : T | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : T | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | GlobalDataFlow.cs:134:40:134:40 | x | -| GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | GlobalDataFlow.cs:134:40:134:40 | x : String | -| GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:20:139:36 | delegate call | -| GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:20:139:36 | delegate call : String | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : Object | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : Object | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : Object | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : Object | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : Object | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : Object | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : String | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : String | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : String | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : String | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : T | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : T | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : T | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : T | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : T | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : T | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : Object | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : Object | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : Object | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : String | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : String | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : String | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : T | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : T | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : T | -| GlobalDataFlow.cs:143:31:143:36 | delegate creation of type Func : Func | GlobalDataFlow.cs:364:41:364:41 | f | -| GlobalDataFlow.cs:143:31:143:36 | delegate creation of type Func : Func | GlobalDataFlow.cs:364:41:364:41 | f : Func | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | GlobalDataFlow.cs:364:46:364:46 | x : Object | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | GlobalDataFlow.cs:364:46:364:46 | x : String | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | GlobalDataFlow.cs:364:46:364:46 | x : T | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : Object | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : Object | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : Object | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : String | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : String | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : String | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : T | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : T | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : T | -| GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) : String | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) : String | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) : T | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) : T | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : String | GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : String | GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : String | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : String | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : T | GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : T | GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : T | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : T | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:147:30:147:35 | delegate creation of type Func : Func | GlobalDataFlow.cs:364:41:364:41 | f | -| GlobalDataFlow.cs:147:30:147:35 | delegate creation of type Func : Func | GlobalDataFlow.cs:364:41:364:41 | f : Func | -| GlobalDataFlow.cs:147:38:147:39 | "" : String | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc | -| GlobalDataFlow.cs:147:38:147:39 | "" : String | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:147:38:147:39 | "" : String | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:147:38:147:39 | "" : String | GlobalDataFlow.cs:364:46:364:46 | x : String | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : String | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : String | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : String | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : String | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : T | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : T | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : T | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : T | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:149:30:149:36 | (...) => ... : Func | GlobalDataFlow.cs:364:41:364:41 | f | -| GlobalDataFlow.cs:149:30:149:36 | (...) => ... : Func | GlobalDataFlow.cs:364:41:364:41 | f : Func | -| GlobalDataFlow.cs:149:35:149:36 | "" : String | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:149:35:149:36 | "" : String | GlobalDataFlow.cs:366:16:366:19 | delegate call : String | -| GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : Object | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : Object | GlobalDataFlow.cs:364:46:364:46 | x : Object | -| GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : String | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : String | GlobalDataFlow.cs:364:46:364:46 | x : String | -| GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : T | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : T | GlobalDataFlow.cs:364:46:364:46 | x : T | -| GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 | -| GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 | -| GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:153:13:153:25 | SSA def(sink6) : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | -| GlobalDataFlow.cs:153:13:153:25 | SSA def(sink6) : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 : String | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | GlobalDataFlow.cs:153:13:153:25 | SSA def(sink6) | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | GlobalDataFlow.cs:153:13:153:25 | SSA def(sink6) : String | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 : String | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:316:12:316:14 | this | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:316:12:316:14 | this : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:321:10:321:15 | this | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:321:10:321:15 | this : DataFlow | -| GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | -| GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 : String | -| GlobalDataFlow.cs:158:13:158:22 | SSA def(sink8) : String | GlobalDataFlow.cs:159:20:159:24 | access to local variable sink8 | -| GlobalDataFlow.cs:158:13:158:22 | SSA def(sink8) : String | GlobalDataFlow.cs:159:20:159:24 | access to local variable sink8 : String | -| GlobalDataFlow.cs:158:21:158:22 | "" : String | GlobalDataFlow.cs:158:13:158:22 | SSA def(sink8) | -| GlobalDataFlow.cs:158:21:158:22 | "" : String | GlobalDataFlow.cs:158:13:158:22 | SSA def(sink8) : String | -| GlobalDataFlow.cs:158:21:158:22 | "" : String | GlobalDataFlow.cs:159:20:159:24 | access to local variable sink8 | -| GlobalDataFlow.cs:158:21:158:22 | "" : String | GlobalDataFlow.cs:159:20:159:24 | access to local variable sink8 : String | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:326:10:326:15 | this | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:326:10:326:15 | this : DataFlow | -| GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | -| GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 : String | -| GlobalDataFlow.cs:161:13:161:31 | SSA def(sink12) : IEnumerable | GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | -| GlobalDataFlow.cs:161:13:161:31 | SSA def(sink12) : IEnumerable | GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 : IEnumerable | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | GlobalDataFlow.cs:161:13:161:31 | SSA def(sink12) | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | GlobalDataFlow.cs:161:13:161:31 | SSA def(sink12) : IEnumerable | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 : IEnumerable | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:331:25:331:32 | this | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:331:25:331:32 | this : DataFlow | -| GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 : String | -| GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) : T | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) : T | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 : T | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) : String | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 : String | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : T | GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : T | GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) : T | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : T | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : T | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 : T | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | GlobalDataFlow.cs:378:39:378:45 | tainted | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | GlobalDataFlow.cs:378:39:378:45 | tainted : String | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : T | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | GlobalDataFlow.cs:378:39:378:45 | tainted | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | GlobalDataFlow.cs:378:39:378:45 | tainted : T | -| GlobalDataFlow.cs:167:9:167:27 | SSA def(nonSink0) : String | GlobalDataFlow.cs:168:15:168:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:167:9:167:27 | SSA def(nonSink0) : String | GlobalDataFlow.cs:168:15:168:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:167:20:167:27 | call to method NonOut : String | GlobalDataFlow.cs:167:9:167:27 | SSA def(nonSink0) | -| GlobalDataFlow.cs:167:20:167:27 | call to method NonOut : String | GlobalDataFlow.cs:167:9:167:27 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:167:20:167:27 | call to method NonOut : String | GlobalDataFlow.cs:168:15:168:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:167:20:167:27 | call to method NonOut : String | GlobalDataFlow.cs:168:15:168:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:338:12:338:17 | this | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:338:12:338:17 | this : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:343:10:343:18 | this | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:343:10:343:18 | this : DataFlow | -| GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) : String | GlobalDataFlow.cs:170:15:170:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) : String | GlobalDataFlow.cs:170:15:170:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) : String | GlobalDataFlow.cs:171:23:171:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) : String | GlobalDataFlow.cs:171:23:171:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:170:15:170:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:171:23:171:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:170:15:170:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:171:23:171:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:348:10:348:18 | this | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:348:10:348:18 | this : DataFlow | -| GlobalDataFlow.cs:171:23:171:30 | SSA def(nonSink0) : String | GlobalDataFlow.cs:172:15:172:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:171:23:171:30 | SSA def(nonSink0) : String | GlobalDataFlow.cs:172:15:172:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) : String | GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) : String | GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) : String | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 | -| GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) : String | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:353:25:353:35 | this | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:353:25:353:35 | this : DataFlow | -| GlobalDataFlow.cs:173:20:173:40 | call to method First : String | GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) | -| GlobalDataFlow.cs:173:20:173:40 | call to method First : String | GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:173:20:173:40 | call to method First : String | GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:173:20:173:40 | call to method First : String | GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:173:20:173:40 | call to method First : String | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 | -| GlobalDataFlow.cs:173:20:173:40 | call to method First : String | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 | -| GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:175:9:175:44 | SSA def(nonSink0) : String | GlobalDataFlow.cs:176:15:176:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:175:9:175:44 | SSA def(nonSink0) : String | GlobalDataFlow.cs:176:15:176:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam : String | GlobalDataFlow.cs:175:9:175:44 | SSA def(nonSink0) | -| GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam : String | GlobalDataFlow.cs:175:9:175:44 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam : String | GlobalDataFlow.cs:176:15:176:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam : String | GlobalDataFlow.cs:176:15:176:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam | -| GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam : String | -| GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | GlobalDataFlow.cs:385:42:385:51 | nonTainted | -| GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | -| GlobalDataFlow.cs:179:22:179:48 | SSA def(out) : Func | GlobalDataFlow.cs:180:21:180:24 | access to local variable out | -| GlobalDataFlow.cs:179:22:179:48 | SSA def(out) : Func | GlobalDataFlow.cs:180:21:180:24 | access to local variable out : Func | -| GlobalDataFlow.cs:179:29:179:48 | (...) => ... : Func | GlobalDataFlow.cs:179:22:179:48 | SSA def(out) | -| GlobalDataFlow.cs:179:29:179:48 | (...) => ... : Func | GlobalDataFlow.cs:179:22:179:48 | SSA def(out) : Func | -| GlobalDataFlow.cs:179:29:179:48 | (...) => ... : Func | GlobalDataFlow.cs:180:21:180:24 | access to local variable out | -| GlobalDataFlow.cs:179:29:179:48 | (...) => ... : Func | GlobalDataFlow.cs:180:21:180:24 | access to local variable out : Func | -| GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:180:21:180:26 | delegate call | -| GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:180:21:180:26 | delegate call : String | -| GlobalDataFlow.cs:180:13:180:26 | SSA def(sink9) : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | -| GlobalDataFlow.cs:180:13:180:26 | SSA def(sink9) : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 : String | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:180:13:180:26 | SSA def(sink9) | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:180:13:180:26 | SSA def(sink9) : String | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 : String | -| GlobalDataFlow.cs:184:22:184:38 | SSA def(nonOut) : Func | GlobalDataFlow.cs:185:20:185:25 | access to local variable nonOut | -| GlobalDataFlow.cs:184:22:184:38 | SSA def(nonOut) : Func | GlobalDataFlow.cs:185:20:185:25 | access to local variable nonOut : Func | -| GlobalDataFlow.cs:184:31:184:38 | (...) => ... : Func | GlobalDataFlow.cs:184:22:184:38 | SSA def(nonOut) | -| GlobalDataFlow.cs:184:31:184:38 | (...) => ... : Func | GlobalDataFlow.cs:184:22:184:38 | SSA def(nonOut) : Func | -| GlobalDataFlow.cs:184:31:184:38 | (...) => ... : Func | GlobalDataFlow.cs:185:20:185:25 | access to local variable nonOut | -| GlobalDataFlow.cs:184:31:184:38 | (...) => ... : Func | GlobalDataFlow.cs:185:20:185:25 | access to local variable nonOut : Func | -| GlobalDataFlow.cs:184:37:184:38 | "" : String | GlobalDataFlow.cs:185:20:185:27 | delegate call | -| GlobalDataFlow.cs:184:37:184:38 | "" : String | GlobalDataFlow.cs:185:20:185:27 | delegate call : String | -| GlobalDataFlow.cs:185:9:185:27 | SSA def(nonSink0) : String | GlobalDataFlow.cs:186:15:186:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:185:9:185:27 | SSA def(nonSink0) : String | GlobalDataFlow.cs:186:15:186:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:185:20:185:27 | delegate call : String | GlobalDataFlow.cs:185:9:185:27 | SSA def(nonSink0) | -| GlobalDataFlow.cs:185:20:185:27 | delegate call : String | GlobalDataFlow.cs:185:9:185:27 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:185:20:185:27 | delegate call : String | GlobalDataFlow.cs:186:15:186:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:185:20:185:27 | delegate call : String | GlobalDataFlow.cs:186:15:186:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : Lazy | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : Lazy | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 : Lazy | -| GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 : String | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : Lazy | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 : Lazy | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : String | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 : String | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : String | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:189:22:189:48 | access to property Value | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 : String | -| GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : Lazy | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : Lazy | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 : Lazy | -| GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : String | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : String | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:193:20:193:43 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) | -| GlobalDataFlow.cs:193:20:193:43 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : Lazy | -| GlobalDataFlow.cs:193:20:193:43 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:193:20:193:43 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 : Lazy | -| GlobalDataFlow.cs:193:20:193:49 | access to property Value : String | GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) | -| GlobalDataFlow.cs:193:20:193:49 | access to property Value : String | GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:193:20:193:49 | access to property Value : String | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:193:20:193:49 | access to property Value : String | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) | -| GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:193:20:193:49 | access to property Value | -| GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:193:20:193:49 | access to property Value : String | -| GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:197:13:197:32 | SSA def(sink19) : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs:197:13:197:32 | SSA def(sink19) : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 : String | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:197:13:197:32 | SSA def(sink19) | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:197:13:197:32 | SSA def(sink19) : String | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 : String | -| GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | GlobalDataFlow.cs:415:9:415:11 | this | -| GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | GlobalDataFlow.cs:415:9:415:11 | this : DataFlow | -| GlobalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:202:15:202:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:202:15:202:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty : String | GlobalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty : String | GlobalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty : String | GlobalDataFlow.cs:202:15:202:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty : String | GlobalDataFlow.cs:202:15:202:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | GlobalDataFlow.cs:420:9:420:11 | this | -| GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | GlobalDataFlow.cs:420:9:420:11 | this : DataFlow | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:208:30:208:92 | SSA def(f1) : Func | GlobalDataFlow.cs:210:37:210:38 | access to local variable f1 | -| GlobalDataFlow.cs:208:30:208:92 | SSA def(f1) : Func | GlobalDataFlow.cs:210:37:210:38 | access to local variable f1 : Func | -| GlobalDataFlow.cs:208:30:208:92 | SSA def(f1) : Func | GlobalDataFlow.cs:220:41:220:42 | access to local variable f1 | -| GlobalDataFlow.cs:208:30:208:92 | SSA def(f1) : Func | GlobalDataFlow.cs:220:41:220:42 | access to local variable f1 : Func | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:35:208:92 | (...) => ... : Func | GlobalDataFlow.cs:208:30:208:92 | SSA def(f1) | -| GlobalDataFlow.cs:208:35:208:92 | (...) => ... : Func | GlobalDataFlow.cs:208:30:208:92 | SSA def(f1) : Func | -| GlobalDataFlow.cs:208:35:208:92 | (...) => ... : Func | GlobalDataFlow.cs:210:37:210:38 | access to local variable f1 | -| GlobalDataFlow.cs:208:35:208:92 | (...) => ... : Func | GlobalDataFlow.cs:210:37:210:38 | access to local variable f1 : Func | -| GlobalDataFlow.cs:208:35:208:92 | (...) => ... : Func | GlobalDataFlow.cs:220:41:220:42 | access to local variable f1 | -| GlobalDataFlow.cs:208:35:208:92 | (...) => ... : Func | GlobalDataFlow.cs:220:41:220:42 | access to local variable f1 : Func | -| GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 | -| GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 : String | -| GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 | -| GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 : String | -| GlobalDataFlow.cs:209:66:209:90 | SSA def(f2) : Expression> | GlobalDataFlow.cs:212:37:212:38 | access to local variable f2 | -| GlobalDataFlow.cs:209:66:209:90 | SSA def(f2) : Expression> | GlobalDataFlow.cs:212:37:212:38 | access to local variable f2 : Expression> | -| GlobalDataFlow.cs:209:66:209:90 | SSA def(f2) : Expression> | GlobalDataFlow.cs:222:37:222:38 | access to local variable f2 | -| GlobalDataFlow.cs:209:66:209:90 | SSA def(f2) : Expression> | GlobalDataFlow.cs:222:37:222:38 | access to local variable f2 : Expression> | -| GlobalDataFlow.cs:209:71:209:71 | x : String | GlobalDataFlow.cs:209:89:209:89 | access to parameter x | -| GlobalDataFlow.cs:209:71:209:71 | x : String | GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | -| GlobalDataFlow.cs:209:71:209:90 | (...) => ... : Expression> | GlobalDataFlow.cs:209:66:209:90 | SSA def(f2) | -| GlobalDataFlow.cs:209:71:209:90 | (...) => ... : Expression> | GlobalDataFlow.cs:209:66:209:90 | SSA def(f2) : Expression> | -| GlobalDataFlow.cs:209:71:209:90 | (...) => ... : Expression> | GlobalDataFlow.cs:212:37:212:38 | access to local variable f2 | -| GlobalDataFlow.cs:209:71:209:90 | (...) => ... : Expression> | GlobalDataFlow.cs:212:37:212:38 | access to local variable f2 : Expression> | -| GlobalDataFlow.cs:209:71:209:90 | (...) => ... : Expression> | GlobalDataFlow.cs:222:37:222:38 | access to local variable f2 | -| GlobalDataFlow.cs:209:71:209:90 | (...) => ... : Expression> | GlobalDataFlow.cs:222:37:222:38 | access to local variable f2 : Expression> | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : String | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : String | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : String | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : String | GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : String | GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : T | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : T | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : T | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : T | GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : T | GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : String | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:298:32:298:41 | sinkParam9 | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | -| GlobalDataFlow.cs:210:13:210:39 | SSA def(sink24) : IEnumerable | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 | -| GlobalDataFlow.cs:210:13:210:39 | SSA def(sink24) : IEnumerable | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 : IEnumerable | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:210:22:210:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:210:13:210:39 | SSA def(sink24) | -| GlobalDataFlow.cs:210:22:210:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:210:13:210:39 | SSA def(sink24) : IEnumerable | -| GlobalDataFlow.cs:210:22:210:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 | -| GlobalDataFlow.cs:210:22:210:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 : IEnumerable | -| GlobalDataFlow.cs:210:37:210:38 | access to local variable f1 : Func | GlobalDataFlow.cs:220:41:220:42 | access to local variable f1 | -| GlobalDataFlow.cs:210:37:210:38 | access to local variable f1 : Func | GlobalDataFlow.cs:220:41:220:42 | access to local variable f1 : Func | -| GlobalDataFlow.cs:212:13:212:39 | SSA def(sink25) : IQueryable | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 | -| GlobalDataFlow.cs:212:13:212:39 | SSA def(sink25) : IQueryable | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 : IQueryable | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:209:71:209:71 | x | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:209:71:209:71 | x : IQueryable | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:212:22:212:39 | call to method Select : IQueryable | GlobalDataFlow.cs:212:13:212:39 | SSA def(sink25) | -| GlobalDataFlow.cs:212:22:212:39 | call to method Select : IQueryable | GlobalDataFlow.cs:212:13:212:39 | SSA def(sink25) : IQueryable | -| GlobalDataFlow.cs:212:22:212:39 | call to method Select : IQueryable | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 | -| GlobalDataFlow.cs:212:22:212:39 | call to method Select : IQueryable | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 : IQueryable | -| GlobalDataFlow.cs:212:37:212:38 | access to local variable f2 : Expression> | GlobalDataFlow.cs:222:37:222:38 | access to local variable f2 | -| GlobalDataFlow.cs:212:37:212:38 | access to local variable f2 : Expression> | GlobalDataFlow.cs:222:37:222:38 | access to local variable f2 : Expression> | -| GlobalDataFlow.cs:214:13:214:49 | SSA def(sink26) : IEnumerable | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 | -| GlobalDataFlow.cs:214:13:214:49 | SSA def(sink26) : IEnumerable | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 : IEnumerable | -| GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 | -| GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | -| GlobalDataFlow.cs:214:22:214:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:214:13:214:49 | SSA def(sink26) | -| GlobalDataFlow.cs:214:22:214:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:214:13:214:49 | SSA def(sink26) : IEnumerable | -| GlobalDataFlow.cs:214:22:214:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 | -| GlobalDataFlow.cs:214:22:214:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 : IEnumerable | -| GlobalDataFlow.cs:218:30:218:95 | SSA def(f3) : Func | GlobalDataFlow.cs:224:37:224:38 | access to local variable f3 | -| GlobalDataFlow.cs:218:30:218:95 | SSA def(f3) : Func | GlobalDataFlow.cs:224:37:224:38 | access to local variable f3 : Func | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:35:218:95 | (...) => ... : Func | GlobalDataFlow.cs:218:30:218:95 | SSA def(f3) | -| GlobalDataFlow.cs:218:35:218:95 | (...) => ... : Func | GlobalDataFlow.cs:218:30:218:95 | SSA def(f3) : Func | -| GlobalDataFlow.cs:218:35:218:95 | (...) => ... : Func | GlobalDataFlow.cs:224:37:224:38 | access to local variable f3 | -| GlobalDataFlow.cs:218:35:218:95 | (...) => ... : Func | GlobalDataFlow.cs:224:37:224:38 | access to local variable f3 : Func | -| GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 | -| GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 : String | -| GlobalDataFlow.cs:219:66:219:92 | SSA def(f4) : Expression> | GlobalDataFlow.cs:226:37:226:38 | access to local variable f4 | -| GlobalDataFlow.cs:219:66:219:92 | SSA def(f4) : Expression> | GlobalDataFlow.cs:226:37:226:38 | access to local variable f4 : Expression> | -| GlobalDataFlow.cs:219:71:219:71 | x : String | GlobalDataFlow.cs:219:91:219:91 | access to parameter x | -| GlobalDataFlow.cs:219:71:219:71 | x : String | GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | -| GlobalDataFlow.cs:219:71:219:92 | (...) => ... : Expression> | GlobalDataFlow.cs:219:66:219:92 | SSA def(f4) | -| GlobalDataFlow.cs:219:71:219:92 | (...) => ... : Expression> | GlobalDataFlow.cs:219:66:219:92 | SSA def(f4) : Expression> | -| GlobalDataFlow.cs:219:71:219:92 | (...) => ... : Expression> | GlobalDataFlow.cs:226:37:226:38 | access to local variable f4 | -| GlobalDataFlow.cs:219:71:219:92 | (...) => ... : Expression> | GlobalDataFlow.cs:226:37:226:38 | access to local variable f4 : Expression> | -| GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : String | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 | -| GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : String | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | -| GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : T | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 | -| GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : T | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | -| GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck | -| GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : String | -| GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | GlobalDataFlow.cs:310:34:310:45 | nonSinkParam | -| GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : String | -| GlobalDataFlow.cs:220:13:220:43 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:221:15:221:21 | access to local variable nonSink | -| GlobalDataFlow.cs:220:13:220:43 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:221:15:221:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:220:23:220:43 | call to method Select : IEnumerable | GlobalDataFlow.cs:220:13:220:43 | SSA def(nonSink) | -| GlobalDataFlow.cs:220:23:220:43 | call to method Select : IEnumerable | GlobalDataFlow.cs:220:13:220:43 | SSA def(nonSink) : IEnumerable | -| GlobalDataFlow.cs:220:23:220:43 | call to method Select : IEnumerable | GlobalDataFlow.cs:221:15:221:21 | access to local variable nonSink | -| GlobalDataFlow.cs:220:23:220:43 | call to method Select : IEnumerable | GlobalDataFlow.cs:221:15:221:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink | -| GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IQueryable | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink | -| GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IQueryable | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IQueryable | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:209:71:209:71 | x | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:209:71:209:71 | x : IQueryable | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) | -| GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IQueryable | -| GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink | -| GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IQueryable | -| GlobalDataFlow.cs:224:9:224:39 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:225:15:225:21 | access to local variable nonSink | -| GlobalDataFlow.cs:224:9:224:39 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:225:15:225:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:218:35:218:46 | nonSinkParam | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : IQueryable | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:224:19:224:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:224:9:224:39 | SSA def(nonSink) | -| GlobalDataFlow.cs:224:19:224:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:224:9:224:39 | SSA def(nonSink) : IEnumerable | -| GlobalDataFlow.cs:224:19:224:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:225:15:225:21 | access to local variable nonSink | -| GlobalDataFlow.cs:224:19:224:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:225:15:225:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink | -| GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IQueryable | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink | -| GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IQueryable | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IQueryable | -| GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:219:71:219:71 | x | -| GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:219:71:219:71 | x : IQueryable | -| GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted | -| GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) | -| GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IQueryable | -| GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink | -| GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IQueryable | -| GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink | -| GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 | -| GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | -| GlobalDataFlow.cs:228:19:228:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) | -| GlobalDataFlow.cs:228:19:228:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) : IEnumerable | -| GlobalDataFlow.cs:228:19:228:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink | -| GlobalDataFlow.cs:228:19:228:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : String | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : String | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 : String | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : T | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : T | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 : T | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : String | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : String | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 : String | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : T | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : T | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : T | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 : T | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : T | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 : T | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 : String | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : T | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : T | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : T | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 : T | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : T | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 : T | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 : String | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : T | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : T | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 : T | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 : String | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : T | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : T | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 : T | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 : String | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : T | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : T | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 : T | -| GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : String | GlobalDataFlow.cs:272:15:272:27 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : String | GlobalDataFlow.cs:272:15:272:27 | access to parameter nonSinkParam0 : String | -| GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : T | GlobalDataFlow.cs:272:15:272:27 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : T | GlobalDataFlow.cs:272:15:272:27 | access to parameter nonSinkParam0 : T | -| GlobalDataFlow.cs:275:26:275:26 | x : Object | GlobalDataFlow.cs:277:37:277:37 | access to parameter x | -| GlobalDataFlow.cs:275:26:275:26 | x : Object | GlobalDataFlow.cs:277:37:277:37 | access to parameter x : Object | -| GlobalDataFlow.cs:275:26:275:26 | x : String | GlobalDataFlow.cs:277:37:277:37 | access to parameter x | -| GlobalDataFlow.cs:275:26:275:26 | x : String | GlobalDataFlow.cs:277:37:277:37 | access to parameter x : String | -| GlobalDataFlow.cs:275:26:275:26 | x : T | GlobalDataFlow.cs:277:37:277:37 | access to parameter x | -| GlobalDataFlow.cs:275:26:275:26 | x : T | GlobalDataFlow.cs:277:37:277:37 | access to parameter x | -| GlobalDataFlow.cs:275:26:275:26 | x : T | GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | -| GlobalDataFlow.cs:275:26:275:26 | x : T | GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:16:278:16 | (...) ... : Object | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : Object | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : Object | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:16:278:16 | (...) ... : String | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : String | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : String | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:16:278:16 | (...) ... : Object | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : Object | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : Object | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:16:278:16 | (...) ... : String | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : String | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : String | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | -| GlobalDataFlow.cs:277:27:277:28 | x0 : Object | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 | -| GlobalDataFlow.cs:277:27:277:28 | x0 : Object | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : Object | -| GlobalDataFlow.cs:277:27:277:28 | x0 : String | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 | -| GlobalDataFlow.cs:277:27:277:28 | x0 : String | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : String | -| GlobalDataFlow.cs:277:27:277:28 | x0 : T | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 | -| GlobalDataFlow.cs:277:27:277:28 | x0 : T | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 | -| GlobalDataFlow.cs:277:27:277:28 | x0 : T | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : T | -| GlobalDataFlow.cs:277:27:277:28 | x0 : T | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : T | -| GlobalDataFlow.cs:277:27:277:34 | (...) => ... : Func | GlobalDataFlow.cs:364:41:364:41 | f | -| GlobalDataFlow.cs:277:27:277:34 | (...) => ... : Func | GlobalDataFlow.cs:364:41:364:41 | f : Func | -| GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : T | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : T | GlobalDataFlow.cs:366:16:366:19 | delegate call : T | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : Object | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : Object | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : Object | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : Object | GlobalDataFlow.cs:364:46:364:46 | x : Object | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : String | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : String | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : String | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : String | GlobalDataFlow.cs:364:46:364:46 | x : String | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:364:46:364:46 | x : T | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:364:46:364:46 | x : T | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | GlobalDataFlow.cs:278:16:278:16 | (...) ... : Object | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : Object | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : Object | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | GlobalDataFlow.cs:278:16:278:16 | (...) ... : String | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : String | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : String | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:70:21:70:46 | call to method Return | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : T | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:100:24:100:33 | call to method Return | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : T | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:366:16:366:19 | delegate call : T | -| GlobalDataFlow.cs:278:28:278:37 | default(...) : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:28:278:37 | default(...) : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : Object | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : String | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : Object | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:283:13:283:13 | access to parameter x | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:283:13:283:13 | access to parameter x : Object | -| GlobalDataFlow.cs:281:32:281:32 | x : String | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:281:32:281:32 | x : String | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : String | -| GlobalDataFlow.cs:281:32:281:32 | x : String | GlobalDataFlow.cs:283:13:283:13 | access to parameter x | -| GlobalDataFlow.cs:281:32:281:32 | x : String | GlobalDataFlow.cs:283:13:283:13 | access to parameter x : String | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:13:283:13 | access to parameter x | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:13:283:13 | access to parameter x | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | -| GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) | -| GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : T | -| GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : Object | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : Object | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : Object | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : String | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : String | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : String | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | -| GlobalDataFlow.cs:284:9:284:22 | SSA def(z) : T | GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) | -| GlobalDataFlow.cs:284:9:284:22 | SSA def(z) : T | GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:284:13:284:22 | default(...) : T | GlobalDataFlow.cs:284:9:284:22 | SSA def(z) | -| GlobalDataFlow.cs:284:13:284:22 | default(...) : T | GlobalDataFlow.cs:284:9:284:22 | SSA def(z) : T | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : Object | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:289:13:289:13 | access to parameter x | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:289:13:289:13 | access to parameter x : Object | -| GlobalDataFlow.cs:287:32:287:32 | x : String | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:287:32:287:32 | x : String | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : String | -| GlobalDataFlow.cs:287:32:287:32 | x : String | GlobalDataFlow.cs:289:13:289:13 | access to parameter x | -| GlobalDataFlow.cs:287:32:287:32 | x : String | GlobalDataFlow.cs:289:13:289:13 | access to parameter x : String | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:13:289:13 | access to parameter x | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:13:289:13 | access to parameter x | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | -| GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) | -| GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | -| GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) | -| GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : T | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : Object | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : Object | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : Object | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : String | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : String | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : String | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : String | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : String | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : T | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : T | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : T | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : T | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : T | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : T | -| GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : String | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : String | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : String | -| GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : T | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : T | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : T | -| GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : T | GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 | -| GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : T | GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : T | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : String | GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : String | GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : String | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : String | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : T | GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : T | GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : T | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : T | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : T | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : T | -| GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : T | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : T | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : T | -| GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : T | GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck | -| GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : T | GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : T | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:323:9:323:26 | SSA def(x) : String | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) | -| GlobalDataFlow.cs:323:9:323:26 | SSA def(x) : String | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | -| GlobalDataFlow.cs:323:13:323:26 | "taint source" : String | GlobalDataFlow.cs:323:9:323:26 | SSA def(x) | -| GlobalDataFlow.cs:323:13:323:26 | "taint source" : String | GlobalDataFlow.cs:323:9:323:26 | SSA def(x) : String | -| GlobalDataFlow.cs:328:9:328:26 | SSA def(x) : String | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) | -| GlobalDataFlow.cs:328:9:328:26 | SSA def(x) : String | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | -| GlobalDataFlow.cs:328:13:328:26 | "taint source" : String | GlobalDataFlow.cs:328:9:328:26 | SSA def(x) | -| GlobalDataFlow.cs:328:13:328:26 | "taint source" : String | GlobalDataFlow.cs:328:9:328:26 | SSA def(x) : String | -| GlobalDataFlow.cs:333:22:333:23 | "" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | -| GlobalDataFlow.cs:333:22:333:23 | "" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | -| GlobalDataFlow.cs:334:22:334:35 | "taint source" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | -| GlobalDataFlow.cs:334:22:334:35 | "taint source" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | -| GlobalDataFlow.cs:335:22:335:23 | "" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | -| GlobalDataFlow.cs:335:22:335:23 | "" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | -| GlobalDataFlow.cs:340:16:340:17 | "" : String | GlobalDataFlow.cs:167:20:167:27 | call to method NonOut | -| GlobalDataFlow.cs:340:16:340:17 | "" : String | GlobalDataFlow.cs:167:20:167:27 | call to method NonOut : String | -| GlobalDataFlow.cs:340:16:340:17 | "" : String | GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:340:16:340:17 | "" : String | GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:345:9:345:14 | SSA def(x) : String | GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) | -| GlobalDataFlow.cs:345:9:345:14 | SSA def(x) : String | GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:345:13:345:14 | "" : String | GlobalDataFlow.cs:345:9:345:14 | SSA def(x) | -| GlobalDataFlow.cs:345:13:345:14 | "" : String | GlobalDataFlow.cs:345:9:345:14 | SSA def(x) : String | -| GlobalDataFlow.cs:350:9:350:14 | SSA def(x) : String | GlobalDataFlow.cs:171:23:171:30 | SSA def(nonSink0) | -| GlobalDataFlow.cs:350:9:350:14 | SSA def(x) : String | GlobalDataFlow.cs:171:23:171:30 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:350:13:350:14 | "" : String | GlobalDataFlow.cs:350:9:350:14 | SSA def(x) | -| GlobalDataFlow.cs:350:13:350:14 | "" : String | GlobalDataFlow.cs:350:9:350:14 | SSA def(x) : String | -| GlobalDataFlow.cs:355:22:355:23 | "" : IEnumerable | GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield | -| GlobalDataFlow.cs:355:22:355:23 | "" : IEnumerable | GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield : IEnumerable | -| GlobalDataFlow.cs:356:22:356:23 | "" : IEnumerable | GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield | -| GlobalDataFlow.cs:356:22:356:23 | "" : IEnumerable | GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield : IEnumerable | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a : Action | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a : Action | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a : Action | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a : Action | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | -| GlobalDataFlow.cs:359:41:359:41 | x : T | GlobalDataFlow.cs:361:11:361:11 | access to parameter x | -| GlobalDataFlow.cs:359:41:359:41 | x : T | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:53:15:53:15 | x | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:53:15:53:15 | x : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:245:26:245:35 | sinkParam3 | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | GlobalDataFlow.cs:53:15:53:15 | x | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | GlobalDataFlow.cs:53:15:53:15 | x : T | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : T | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | GlobalDataFlow.cs:245:26:245:35 | sinkParam3 | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : T | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : String | GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : String | GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:275:26:275:26 | x : Object | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:275:26:275:26 | x : Object | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:277:27:277:28 | x0 | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:277:27:277:28 | x0 : Object | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:366:16:366:19 | delegate call : Object | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:366:16:366:19 | delegate call : Object | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:366:16:366:19 | delegate call : Object | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:277:27:277:28 | x0 | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:277:27:277:28 | x0 : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:275:26:275:26 | x : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:275:26:275:26 | x : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:275:26:275:26 | x : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:277:27:277:28 | x0 | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:277:27:277:28 | x0 | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:277:27:277:28 | x0 : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:277:27:277:28 | x0 : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call : T | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a : MyDelegate | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a : MyDelegate | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a : MyDelegate | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a : MyDelegate | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a : MyDelegate | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:255:26:255:35 | sinkParam5 | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:255:26:255:35 | sinkParam5 | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:260:26:260:35 | sinkParam6 | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:260:26:260:35 | sinkParam6 | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : T | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : T | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : T | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : T | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : T | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : T | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : T | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : T | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : T | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : T | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : T | -| GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam | -| GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam | -| GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam : String | -| GlobalDataFlow.cs:398:62:398:63 | "" : String | GlobalDataFlow.cs:32:15:32:35 | access to property NonSinkProperty1 | -| GlobalDataFlow.cs:398:62:398:63 | "" : String | GlobalDataFlow.cs:32:15:32:35 | access to property NonSinkProperty1 : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:28:404:32 | access to parameter value | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:28:404:32 | access to parameter value | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:30:410:34 | access to parameter value | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:30:410:34 | access to parameter value | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:415:22:415:35 | "taint source" : String | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty | -| GlobalDataFlow.cs:415:22:415:35 | "taint source" : String | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | -| GlobalDataFlow.cs:420:22:420:23 | "" : String | GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty | -| GlobalDataFlow.cs:420:22:420:23 | "" : String | GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty : String | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:27:429:27 | access to parameter e | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:27:429:27 | access to parameter e | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:27:429:27 | access to parameter e | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:429:27:429:27 | access to parameter e | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:429:27:429:27 | access to parameter e | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:429:27:429:27 | access to parameter e : String[] | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:429:27:429:27 | access to parameter e : String[] | -| GlobalDataFlow.cs:426:85:426:85 | f : Func | GlobalDataFlow.cs:431:44:431:44 | access to parameter f | -| GlobalDataFlow.cs:426:85:426:85 | f : Func | GlobalDataFlow.cs:431:44:431:44 | access to parameter f | -| GlobalDataFlow.cs:426:85:426:85 | f : Func | GlobalDataFlow.cs:431:44:431:44 | access to parameter f : Func | -| GlobalDataFlow.cs:426:85:426:85 | f : Func | GlobalDataFlow.cs:431:44:431:44 | access to parameter f : Func | -| GlobalDataFlow.cs:426:85:426:85 | f : Func | GlobalDataFlow.cs:431:44:431:44 | access to parameter f | -| GlobalDataFlow.cs:426:85:426:85 | f : Func | GlobalDataFlow.cs:431:44:431:44 | access to parameter f : Func | -| GlobalDataFlow.cs:428:13:428:17 | SSA def(i) : Int32 | GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) | -| GlobalDataFlow.cs:428:13:428:17 | SSA def(i) : Int32 | GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) : Int32 | -| GlobalDataFlow.cs:428:13:428:17 | SSA def(i) : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i | -| GlobalDataFlow.cs:428:13:428:17 | SSA def(i) : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i : Int32 | -| GlobalDataFlow.cs:428:17:428:17 | 0 : Int32 | GlobalDataFlow.cs:428:13:428:17 | SSA def(i) | -| GlobalDataFlow.cs:428:17:428:17 | 0 : Int32 | GlobalDataFlow.cs:428:13:428:17 | SSA def(i) : Int32 | -| GlobalDataFlow.cs:428:17:428:17 | 0 : Int32 | GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) | -| GlobalDataFlow.cs:428:17:428:17 | 0 : Int32 | GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) : Int32 | -| GlobalDataFlow.cs:428:17:428:17 | 0 : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i | -| GlobalDataFlow.cs:428:17:428:17 | 0 : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i : Int32 | -| GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i | -| GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i : Int32 | -| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:431:17:431:19 | SSA def(i) : Int32 | GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) | -| GlobalDataFlow.cs:431:17:431:19 | SSA def(i) : Int32 | GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) : Int32 | -| GlobalDataFlow.cs:431:17:431:19 | SSA def(i) : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i | -| GlobalDataFlow.cs:431:17:431:19 | SSA def(i) : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i : Int32 | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:80:79:80:79 | x | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:80:79:80:79 | x : T | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:112:84:112:84 | x | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:112:84:112:84 | x : T | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : T | -| Splitting.cs:3:18:3:18 | b : Boolean | Splitting.cs:5:13:5:13 | access to parameter b | -| Splitting.cs:3:18:3:18 | b : Boolean | Splitting.cs:5:13:5:13 | access to parameter b : Boolean | -| Splitting.cs:3:18:3:18 | b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): false] access to parameter b | -| Splitting.cs:3:18:3:18 | b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): false] access to parameter b : Boolean | -| Splitting.cs:3:18:3:18 | b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): true] access to parameter b | -| Splitting.cs:3:18:3:18 | b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): true] access to parameter b : Boolean | -| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:6:17:6:23 | [b (line 3): true] access to parameter tainted | -| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:6:17:6:23 | [b (line 3): true] access to parameter tainted : String | -| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted | -| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | -| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | -| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | -| Splitting.cs:5:13:5:13 | access to parameter b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): false] access to parameter b | -| Splitting.cs:5:13:5:13 | access to parameter b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): false] access to parameter b : Boolean | -| Splitting.cs:5:13:5:13 | access to parameter b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): true] access to parameter b | -| Splitting.cs:5:13:5:13 | access to parameter b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): true] access to parameter b : Boolean | -| Splitting.cs:6:17:6:23 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | -| Splitting.cs:6:17:6:23 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | -| Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | -| Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x : String | -| Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) : T | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | -| Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) : T | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x : T | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : String | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : String | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : String | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : String | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : String | Splitting.cs:11:19:11:19 | access to local variable x : String | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : T | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : T | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : T | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : T | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : T | Splitting.cs:11:19:11:19 | access to local variable x : T | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) : String | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x : String | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : T | Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : T | Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) : T | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : T | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : T | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x : T | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : String | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : String | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:11:19:11:19 | access to local variable x : String | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : T | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : T | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | Splitting.cs:11:19:11:19 | access to local variable x : T | -| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | -| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | -| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | Splitting.cs:16:26:16:26 | x : String | -| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | -| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | -| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:16:26:16:26 | x : String | -| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : String | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : String | Splitting.cs:11:19:11:19 | access to local variable x : String | -| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : T | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : T | Splitting.cs:11:19:11:19 | access to local variable x : T | -| Splitting.cs:16:26:16:26 | x : String | Splitting.cs:16:32:16:32 | access to parameter x | -| Splitting.cs:16:26:16:26 | x : String | Splitting.cs:16:32:16:32 | access to parameter x : String | -| Splitting.cs:16:26:16:26 | x : T | Splitting.cs:16:32:16:32 | access to parameter x | -| Splitting.cs:16:26:16:26 | x : T | Splitting.cs:16:32:16:32 | access to parameter x : T | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : T | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:20:22:20:30 | call to method Return | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:20:22:20:30 | call to method Return : T | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:21:21:21:33 | call to method Return | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:21:21:21:33 | call to method Return : T | -| Splitting.cs:18:24:18:24 | s : String | Splitting.cs:20:29:20:29 | access to parameter s | -| Splitting.cs:18:24:18:24 | s : String | Splitting.cs:20:29:20:29 | access to parameter s | -| Splitting.cs:18:24:18:24 | s : String | Splitting.cs:20:29:20:29 | access to parameter s : String | -| Splitting.cs:18:24:18:24 | s : String | Splitting.cs:20:29:20:29 | access to parameter s : String | -| Splitting.cs:20:22:20:30 | call to method Return : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:20:22:20:30 | call to method Return : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : String | -| Splitting.cs:20:22:20:30 | call to method Return : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:20:22:20:30 | call to method Return : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | -| Splitting.cs:20:22:20:30 | call to method Return : T | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:20:22:20:30 | call to method Return : T | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : T | -| Splitting.cs:20:22:20:30 | call to method Return : T | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:20:22:20:30 | call to method Return : T | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:16:26:16:26 | x : String | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:16:26:16:26 | x : String | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:20:22:20:30 | call to method Return | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:20:22:20:30 | call to method Return | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:20:22:20:30 | call to method Return : String | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:20:22:20:30 | call to method Return : String | -| Splitting.cs:21:9:21:11 | value : String | Splitting.cs:21:28:21:32 | access to parameter value | -| Splitting.cs:21:9:21:11 | value : String | Splitting.cs:21:28:21:32 | access to parameter value | -| Splitting.cs:21:9:21:11 | value : String | Splitting.cs:21:28:21:32 | access to parameter value : String | -| Splitting.cs:21:9:21:11 | value : String | Splitting.cs:21:28:21:32 | access to parameter value : String | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:16:26:16:26 | x : String | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:16:26:16:26 | x : String | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:21:21:21:33 | call to method Return | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:21:21:21:33 | call to method Return | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:21:21:21:33 | call to method Return : String | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:21:21:21:33 | call to method Return : String | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:21:29:24 | [b (line 24): false] this access | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:21:29:24 | [b (line 24): true] this access | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:24:18:24:18 | b : Boolean | Splitting.cs:26:13:26:13 | access to parameter b | -| Splitting.cs:24:18:24:18 | b : Boolean | Splitting.cs:26:13:26:13 | access to parameter b : Boolean | -| Splitting.cs:24:18:24:18 | b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): false] access to parameter b | -| Splitting.cs:24:18:24:18 | b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): false] access to parameter b : Boolean | -| Splitting.cs:24:18:24:18 | b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): true] access to parameter b | -| Splitting.cs:24:18:24:18 | b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): true] access to parameter b : Boolean | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:26:13:26:13 | access to parameter b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): false] access to parameter b | -| Splitting.cs:26:13:26:13 | access to parameter b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): false] access to parameter b : Boolean | -| Splitting.cs:26:13:26:13 | access to parameter b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): true] access to parameter b | -| Splitting.cs:26:13:26:13 | access to parameter b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): true] access to parameter b : Boolean | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:21:9:21:11 | this | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:21:9:21:11 | this : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:21:9:21:11 | this | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:21:9:21:11 | this : Splitting | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:21:9:21:11 | this | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:21:9:21:11 | this : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:21:9:21:11 | this | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:21:9:21:11 | this : Splitting | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:21:9:21:11 | value | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:21:9:21:11 | value : String | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:21:9:21:11 | value | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:21:9:21:11 | value : String | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : String | -| Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : T | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : T | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : T | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : String | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : String | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : String | Splitting.cs:34:19:34:19 | access to local variable x : String | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : T | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : T | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : T | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : T | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : T | Splitting.cs:34:19:34:19 | access to local variable x : T | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | Splitting.cs:20:9:20:11 | this | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | Splitting.cs:20:9:20:11 | this : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:20:9:20:11 | this | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:20:9:20:11 | this : Splitting | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | Splitting.cs:20:9:20:11 | this | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | Splitting.cs:20:9:20:11 | this : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:20:9:20:11 | this | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:20:9:20:11 | this : Splitting | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : String | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : String | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : String | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : String | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : T | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : T | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : T | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : T | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : T | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : T | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : String | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : String | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:34:19:34:19 | access to local variable x : String | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : T | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : T | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | Splitting.cs:34:19:34:19 | access to local variable x : T | -| Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:18:24:18:24 | s | -| Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:18:24:18:24 | s : String | -| Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : String | -| Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:18:24:18:24 | s | -| Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:18:24:18:24 | s : String | -| Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | -| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : String | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : String | Splitting.cs:34:19:34:19 | access to local variable x : String | -| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : T | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : T | Splitting.cs:34:19:34:19 | access to local variable x : T | -| This.cs:9:20:9:20 | this : Sub | This.cs:11:13:11:16 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:11:13:11:16 | this access : Sub | -| This.cs:9:20:9:20 | this : Sub | This.cs:12:9:12:12 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:12:9:12:12 | this access : Sub | -| This.cs:9:20:9:20 | this : Sub | This.cs:12:16:12:19 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:12:16:12:19 | this access : Sub | -| This.cs:9:20:9:20 | this : Sub | This.cs:13:9:13:15 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:13:9:13:15 | this access : Sub | -| This.cs:9:20:9:20 | this : Sub | This.cs:13:11:13:14 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:13:11:13:14 | this access : Sub | -| This.cs:9:20:9:20 | this : Sub | This.cs:15:9:15:12 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:15:9:15:12 | this access : Sub | -| This.cs:9:20:9:20 | this : Sub | This.cs:16:9:16:16 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:9:20:9:20 | this : This | This.cs:11:13:11:16 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:11:13:11:16 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:11:13:11:16 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:11:13:11:16 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:12:9:12:12 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:12:9:12:12 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:12:9:12:12 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:12:9:12:12 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:12:16:12:19 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:12:16:12:19 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:12:16:12:19 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:12:16:12:19 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:13:9:13:15 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:13:9:13:15 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:13:9:13:15 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:13:9:13:15 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:13:11:13:14 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:13:11:13:14 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:13:11:13:14 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:13:11:13:14 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:15:9:15:12 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:15:9:15:12 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:15:9:15:12 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:15:9:15:12 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:16:9:16:16 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:16:9:16:16 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:16:9:16:16 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:16:9:16:16 | this access : This | -| This.cs:9:27:9:31 | other : Sub | This.cs:14:13:14:17 | access to parameter other | -| This.cs:9:27:9:31 | other : Sub | This.cs:14:13:14:17 | access to parameter other : Sub | -| This.cs:9:27:9:31 | other : Sub | This.cs:15:16:15:20 | access to parameter other | -| This.cs:9:27:9:31 | other : Sub | This.cs:15:16:15:20 | access to parameter other : Sub | -| This.cs:9:27:9:31 | other : Sub | This.cs:16:11:16:15 | access to parameter other | -| This.cs:9:27:9:31 | other : Sub | This.cs:16:11:16:15 | access to parameter other : Sub | -| This.cs:9:27:9:31 | other : This | This.cs:14:13:14:17 | access to parameter other | -| This.cs:9:27:9:31 | other : This | This.cs:14:13:14:17 | access to parameter other | -| This.cs:9:27:9:31 | other : This | This.cs:14:13:14:17 | access to parameter other : This | -| This.cs:9:27:9:31 | other : This | This.cs:14:13:14:17 | access to parameter other : This | -| This.cs:9:27:9:31 | other : This | This.cs:15:16:15:20 | access to parameter other | -| This.cs:9:27:9:31 | other : This | This.cs:15:16:15:20 | access to parameter other | -| This.cs:9:27:9:31 | other : This | This.cs:15:16:15:20 | access to parameter other : This | -| This.cs:9:27:9:31 | other : This | This.cs:15:16:15:20 | access to parameter other : This | -| This.cs:9:27:9:31 | other : This | This.cs:16:11:16:15 | access to parameter other | -| This.cs:9:27:9:31 | other : This | This.cs:16:11:16:15 | access to parameter other | -| This.cs:9:27:9:31 | other : This | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:9:27:9:31 | other : This | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:11:13:11:16 | this access : Sub | This.cs:12:9:12:12 | this access | -| This.cs:11:13:11:16 | this access : Sub | This.cs:12:9:12:12 | this access : Sub | -| This.cs:11:13:11:16 | this access : Sub | This.cs:12:16:12:19 | this access | -| This.cs:11:13:11:16 | this access : Sub | This.cs:12:16:12:19 | this access : Sub | -| This.cs:11:13:11:16 | this access : Sub | This.cs:13:9:13:15 | this access | -| This.cs:11:13:11:16 | this access : Sub | This.cs:13:9:13:15 | this access : Sub | -| This.cs:11:13:11:16 | this access : Sub | This.cs:13:11:13:14 | this access | -| This.cs:11:13:11:16 | this access : Sub | This.cs:13:11:13:14 | this access : Sub | -| This.cs:11:13:11:16 | this access : Sub | This.cs:15:9:15:12 | this access | -| This.cs:11:13:11:16 | this access : Sub | This.cs:15:9:15:12 | this access : Sub | -| This.cs:11:13:11:16 | this access : Sub | This.cs:16:9:16:16 | this access | -| This.cs:11:13:11:16 | this access : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:11:13:11:16 | this access : This | This.cs:12:9:12:12 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:12:9:12:12 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:12:9:12:12 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:12:9:12:12 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:12:16:12:19 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:12:16:12:19 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:12:16:12:19 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:12:16:12:19 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:13:9:13:15 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:13:9:13:15 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:13:9:13:15 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:13:9:13:15 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:12:9:12:12 | this access : Sub | This.cs:9:20:9:20 | this | -| This.cs:12:9:12:12 | this access : Sub | This.cs:9:20:9:20 | this : Sub | -| This.cs:12:9:12:12 | this access : Sub | This.cs:12:16:12:19 | this access | -| This.cs:12:9:12:12 | this access : Sub | This.cs:12:16:12:19 | this access : Sub | -| This.cs:12:9:12:12 | this access : Sub | This.cs:13:9:13:15 | this access | -| This.cs:12:9:12:12 | this access : Sub | This.cs:13:9:13:15 | this access : Sub | -| This.cs:12:9:12:12 | this access : Sub | This.cs:13:11:13:14 | this access | -| This.cs:12:9:12:12 | this access : Sub | This.cs:13:11:13:14 | this access : Sub | -| This.cs:12:9:12:12 | this access : Sub | This.cs:15:9:15:12 | this access | -| This.cs:12:9:12:12 | this access : Sub | This.cs:15:9:15:12 | this access : Sub | -| This.cs:12:9:12:12 | this access : Sub | This.cs:16:9:16:16 | this access | -| This.cs:12:9:12:12 | this access : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:12:9:12:12 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:12:9:12:12 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:12:9:12:12 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:12:9:12:12 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:12:9:12:12 | this access : This | This.cs:12:16:12:19 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:12:16:12:19 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:12:16:12:19 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:12:16:12:19 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:13:9:13:15 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:13:9:13:15 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:13:9:13:15 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:13:9:13:15 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:12:16:12:19 | this access : Sub | This.cs:9:27:9:31 | other | -| This.cs:12:16:12:19 | this access : Sub | This.cs:9:27:9:31 | other : Sub | -| This.cs:12:16:12:19 | this access : Sub | This.cs:13:9:13:15 | this access | -| This.cs:12:16:12:19 | this access : Sub | This.cs:13:9:13:15 | this access : Sub | -| This.cs:12:16:12:19 | this access : Sub | This.cs:13:11:13:14 | this access | -| This.cs:12:16:12:19 | this access : Sub | This.cs:13:11:13:14 | this access : Sub | -| This.cs:12:16:12:19 | this access : Sub | This.cs:15:9:15:12 | this access | -| This.cs:12:16:12:19 | this access : Sub | This.cs:15:9:15:12 | this access : Sub | -| This.cs:12:16:12:19 | this access : Sub | This.cs:16:9:16:16 | this access | -| This.cs:12:16:12:19 | this access : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:12:16:12:19 | this access : This | This.cs:9:27:9:31 | other | -| This.cs:12:16:12:19 | this access : This | This.cs:9:27:9:31 | other | -| This.cs:12:16:12:19 | this access : This | This.cs:9:27:9:31 | other : This | -| This.cs:12:16:12:19 | this access : This | This.cs:9:27:9:31 | other : This | -| This.cs:12:16:12:19 | this access : This | This.cs:13:9:13:15 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:13:9:13:15 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:13:9:13:15 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:13:9:13:15 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:13:9:13:15 | this access : Sub | This.cs:9:20:9:20 | this | -| This.cs:13:9:13:15 | this access : Sub | This.cs:9:20:9:20 | this : Sub | -| This.cs:13:9:13:15 | this access : Sub | This.cs:13:11:13:14 | this access | -| This.cs:13:9:13:15 | this access : Sub | This.cs:13:11:13:14 | this access : Sub | -| This.cs:13:9:13:15 | this access : Sub | This.cs:15:9:15:12 | this access | -| This.cs:13:9:13:15 | this access : Sub | This.cs:15:9:15:12 | this access : Sub | -| This.cs:13:9:13:15 | this access : Sub | This.cs:16:9:16:16 | this access | -| This.cs:13:9:13:15 | this access : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:13:9:13:15 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:13:9:13:15 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:13:9:13:15 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:13:9:13:15 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:13:9:13:15 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:13:9:13:15 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:13:9:13:15 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:13:9:13:15 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:13:9:13:15 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:13:9:13:15 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:13:9:13:15 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:13:9:13:15 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:13:9:13:15 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:13:9:13:15 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:13:9:13:15 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:13:9:13:15 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:13:11:13:14 | this access : Sub | This.cs:9:27:9:31 | other | -| This.cs:13:11:13:14 | this access : Sub | This.cs:9:27:9:31 | other : Sub | -| This.cs:13:11:13:14 | this access : Sub | This.cs:15:9:15:12 | this access | -| This.cs:13:11:13:14 | this access : Sub | This.cs:15:9:15:12 | this access : Sub | -| This.cs:13:11:13:14 | this access : Sub | This.cs:16:9:16:16 | this access | -| This.cs:13:11:13:14 | this access : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:13:11:13:14 | this access : This | This.cs:9:27:9:31 | other | -| This.cs:13:11:13:14 | this access : This | This.cs:9:27:9:31 | other | -| This.cs:13:11:13:14 | this access : This | This.cs:9:27:9:31 | other : This | -| This.cs:13:11:13:14 | this access : This | This.cs:9:27:9:31 | other : This | -| This.cs:13:11:13:14 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:13:11:13:14 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:13:11:13:14 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:13:11:13:14 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:13:11:13:14 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:13:11:13:14 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:13:11:13:14 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:13:11:13:14 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:14:13:14:17 | access to parameter other : Sub | This.cs:15:16:15:20 | access to parameter other | -| This.cs:14:13:14:17 | access to parameter other : Sub | This.cs:15:16:15:20 | access to parameter other : Sub | -| This.cs:14:13:14:17 | access to parameter other : Sub | This.cs:16:11:16:15 | access to parameter other | -| This.cs:14:13:14:17 | access to parameter other : Sub | This.cs:16:11:16:15 | access to parameter other : Sub | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:15:16:15:20 | access to parameter other | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:15:16:15:20 | access to parameter other | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:15:16:15:20 | access to parameter other : This | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:15:16:15:20 | access to parameter other : This | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:15:9:15:12 | this access : Sub | This.cs:9:20:9:20 | this | -| This.cs:15:9:15:12 | this access : Sub | This.cs:9:20:9:20 | this : Sub | -| This.cs:15:9:15:12 | this access : Sub | This.cs:16:9:16:16 | this access | -| This.cs:15:9:15:12 | this access : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:15:9:15:12 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:15:9:15:12 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:15:9:15:12 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:15:9:15:12 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:15:9:15:12 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:15:9:15:12 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:15:9:15:12 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:15:9:15:12 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:15:16:15:20 | access to parameter other : Sub | This.cs:9:27:9:31 | other | -| This.cs:15:16:15:20 | access to parameter other : Sub | This.cs:9:27:9:31 | other : Sub | -| This.cs:15:16:15:20 | access to parameter other : Sub | This.cs:16:11:16:15 | access to parameter other | -| This.cs:15:16:15:20 | access to parameter other : Sub | This.cs:16:11:16:15 | access to parameter other : Sub | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:9:27:9:31 | other | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:9:27:9:31 | other | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:9:27:9:31 | other : This | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:9:27:9:31 | other : This | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:16:9:16:16 | this access : Sub | This.cs:9:20:9:20 | this | -| This.cs:16:9:16:16 | this access : Sub | This.cs:9:20:9:20 | this : Sub | -| This.cs:16:9:16:16 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:16:9:16:16 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:16:9:16:16 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:16:9:16:16 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:16:11:16:15 | access to parameter other : Sub | This.cs:9:27:9:31 | other | -| This.cs:16:11:16:15 | access to parameter other : Sub | This.cs:9:27:9:31 | other : Sub | -| This.cs:16:11:16:15 | access to parameter other : This | This.cs:9:27:9:31 | other | -| This.cs:16:11:16:15 | access to parameter other : This | This.cs:9:27:9:31 | other | -| This.cs:16:11:16:15 | access to parameter other : This | This.cs:9:27:9:31 | other : This | -| This.cs:16:11:16:15 | access to parameter other : This | This.cs:9:27:9:31 | other : This | -| This.cs:17:9:17:18 | malloc : This | This.cs:7:5:7:8 | this | -| This.cs:17:9:17:18 | malloc : This | This.cs:7:5:7:8 | this : This | -| This.cs:24:14:24:15 | this : Sub | This.cs:26:13:26:16 | this access | -| This.cs:24:14:24:15 | this : Sub | This.cs:26:13:26:16 | this access : Sub | -| This.cs:24:14:24:15 | this : Sub | This.cs:26:20:26:23 | this access | -| This.cs:24:14:24:15 | this : Sub | This.cs:26:20:26:23 | this access : Sub | -| This.cs:24:14:24:15 | this : Sub | This.cs:27:13:27:16 | base access | -| This.cs:24:14:24:15 | this : Sub | This.cs:27:13:27:16 | base access : Sub | -| This.cs:24:14:24:15 | this : Sub | This.cs:27:20:27:23 | this access | -| This.cs:24:14:24:15 | this : Sub | This.cs:27:20:27:23 | this access : Sub | -| This.cs:26:13:26:16 | this access : Sub | This.cs:9:20:9:20 | this | -| This.cs:26:13:26:16 | this access : Sub | This.cs:9:20:9:20 | this : Sub | -| This.cs:26:13:26:16 | this access : Sub | This.cs:26:20:26:23 | this access | -| This.cs:26:13:26:16 | this access : Sub | This.cs:26:20:26:23 | this access : Sub | -| This.cs:26:13:26:16 | this access : Sub | This.cs:27:13:27:16 | base access | -| This.cs:26:13:26:16 | this access : Sub | This.cs:27:13:27:16 | base access : Sub | -| This.cs:26:13:26:16 | this access : Sub | This.cs:27:20:27:23 | this access | -| This.cs:26:13:26:16 | this access : Sub | This.cs:27:20:27:23 | this access : Sub | -| This.cs:26:20:26:23 | this access : Sub | This.cs:9:27:9:31 | other | -| This.cs:26:20:26:23 | this access : Sub | This.cs:9:27:9:31 | other : Sub | -| This.cs:26:20:26:23 | this access : Sub | This.cs:27:13:27:16 | base access | -| This.cs:26:20:26:23 | this access : Sub | This.cs:27:13:27:16 | base access : Sub | -| This.cs:26:20:26:23 | this access : Sub | This.cs:27:20:27:23 | this access | -| This.cs:26:20:26:23 | this access : Sub | This.cs:27:20:27:23 | this access : Sub | -| This.cs:27:13:27:16 | base access : Sub | This.cs:9:20:9:20 | this | -| This.cs:27:13:27:16 | base access : Sub | This.cs:9:20:9:20 | this : Sub | -| This.cs:27:13:27:16 | base access : Sub | This.cs:27:20:27:23 | this access | -| This.cs:27:13:27:16 | base access : Sub | This.cs:27:20:27:23 | this access : Sub | -| This.cs:27:13:27:16 | base access : This | This.cs:9:20:9:20 | this | -| This.cs:27:13:27:16 | base access : This | This.cs:9:20:9:20 | this : This | -| This.cs:27:13:27:16 | base access : This | This.cs:27:20:27:23 | this access | -| This.cs:27:13:27:16 | base access : This | This.cs:27:20:27:23 | this access : This | -| This.cs:27:20:27:23 | this access : Sub | This.cs:9:27:9:31 | other | -| This.cs:27:20:27:23 | this access : Sub | This.cs:9:27:9:31 | other : Sub | -| This.cs:27:20:27:23 | this access : This | This.cs:9:27:9:31 | other | -| This.cs:27:20:27:23 | this access : This | This.cs:9:27:9:31 | other : This | -| This.cs:28:13:28:21 | malloc : Sub | This.cs:22:9:22:11 | this | -| This.cs:28:13:28:21 | malloc : Sub | This.cs:22:9:22:11 | this : Sub | diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlowEdges.ql b/csharp/ql/test/library-tests/dataflow/global/DataFlowEdges.ql deleted file mode 100644 index d6d43ededd0..00000000000 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlowEdges.ql +++ /dev/null @@ -1,17 +0,0 @@ -import csharp -import DataFlow -import semmle.code.csharp.dataflow.internal.DataFlowPrivate - -class ConfigAny extends Configuration { - ConfigAny() { this = "ConfigAny" } - - override predicate isSource(Node source) { - source instanceof PostUpdateNode implies source.asExpr() instanceof ObjectCreation - } - - override predicate isSink(Node sink) { - sink instanceof PostUpdateNode implies sink.asExpr() instanceof ObjectCreation - } -} - -query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b } diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected index cc1d49f3557..af0e92f2377 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected @@ -75,7 +75,7 @@ edges | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | +| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | @@ -84,7 +84,7 @@ edges | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : String | +| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | | GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | @@ -100,31 +100,31 @@ edges | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:359:41:359:41 | x : String | +| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:361:41:361:41 | x : String | | GlobalDataFlow.cs:53:15:53:15 | x : String | GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | +| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:359:41:359:41 | x : String | +| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:361:41:361:41 | x : String | | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:373:52:373:52 | x : String | +| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:375:52:375:52 | x : String | | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:373:52:373:52 | x : String | +| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:375:52:375:52 | x : String | | GlobalDataFlow.cs:56:37:56:37 | x : String | GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | +| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:373:52:373:52 | x : String | +| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:375:52:375:52 | x : String | | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:404:9:404:11 | value : String | +| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:406:9:406:11 | value : String | | GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | | GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | @@ -151,36 +151,36 @@ edges | GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : String | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : String | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:323:9:323:26 | SSA def(x) : String | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | -| GlobalDataFlow.cs:323:13:323:26 | "taint source" : String | GlobalDataFlow.cs:323:9:323:26 | SSA def(x) : String | -| GlobalDataFlow.cs:328:9:328:26 | SSA def(x) : String | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | -| GlobalDataFlow.cs:328:13:328:26 | "taint source" : String | GlobalDataFlow.cs:328:9:328:26 | SSA def(x) : String | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:53:15:53:15 | x : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:415:22:415:35 | "taint source" : String | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | +| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | +| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | +| GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | +| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | +| GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | +| GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | +| GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | +| GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | +| GlobalDataFlow.cs:361:41:361:41 | x : String | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | +| GlobalDataFlow.cs:361:41:361:41 | x : String | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | +| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | GlobalDataFlow.cs:53:15:53:15 | x : String | +| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | +| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | +| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | +| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | +| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x : String | +| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | +| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | +| GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | +| GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | +| GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | +| GlobalDataFlow.cs:406:9:406:11 | value : String | GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | +| GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | @@ -304,42 +304,42 @@ nodes | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | semmle.label | access to local variable sink10 | | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | semmle.label | access to property OutProperty : String | | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | semmle.label | access to local variable sink19 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | semmle.label | sinkParam0 : String | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | semmle.label | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | semmle.label | access to parameter sinkParam0 | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : String | semmle.label | sinkParam1 : String | -| GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | semmle.label | access to parameter sinkParam1 | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : String | semmle.label | sinkParam3 : String | -| GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | semmle.label | access to parameter sinkParam3 | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | semmle.label | sinkParam4 : String | -| GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | semmle.label | access to parameter sinkParam4 | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | semmle.label | sinkParam5 : String | -| GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | semmle.label | access to parameter sinkParam5 | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | semmle.label | sinkParam6 : String | -| GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | semmle.label | access to parameter sinkParam6 | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | semmle.label | sinkParam7 : String | -| GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | semmle.label | access to parameter sinkParam7 | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:323:9:323:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | -| GlobalDataFlow.cs:323:13:323:26 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:328:9:328:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | -| GlobalDataFlow.cs:328:13:328:26 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:359:41:359:41 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:359:41:359:41 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | semmle.label | tainted : String | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | semmle.label | access to local variable sink11 | -| GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | semmle.label | access to local variable sink11 : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | semmle.label | value : String | -| GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | semmle.label | access to local variable sink20 | -| GlobalDataFlow.cs:415:22:415:35 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | semmle.label | sinkParam0 : String | +| GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | semmle.label | access to parameter sinkParam0 : String | +| GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | semmle.label | access to parameter sinkParam0 | +| GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | semmle.label | sinkParam1 : String | +| GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | semmle.label | access to parameter sinkParam1 | +| GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | semmle.label | sinkParam3 : String | +| GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | semmle.label | access to parameter sinkParam3 | +| GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | semmle.label | sinkParam4 : String | +| GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | semmle.label | access to parameter sinkParam4 | +| GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | semmle.label | sinkParam5 : String | +| GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | semmle.label | access to parameter sinkParam5 | +| GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | semmle.label | sinkParam6 : String | +| GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | semmle.label | access to parameter sinkParam6 | +| GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | semmle.label | sinkParam7 : String | +| GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | semmle.label | access to parameter sinkParam7 | +| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | +| GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | +| GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:361:41:361:41 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:361:41:361:41 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:380:39:380:45 | tainted : String | semmle.label | tainted : String | +| GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | semmle.label | access to local variable sink11 | +| GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | semmle.label | access to local variable sink11 : String | +| GlobalDataFlow.cs:406:9:406:11 | value : String | semmle.label | value : String | +| GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | semmle.label | access to local variable sink20 | +| GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | semmle.label | "taint source" : String | | Splitting.cs:3:28:3:34 | tainted : String | semmle.label | tainted : String | | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | semmle.label | [b (line 3): false] call to method Return : String | | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | semmle.label | [b (line 3): true] call to method Return : String | @@ -368,12 +368,12 @@ nodes | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | access to field SinkField0 | | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | access to local variable sink0 | | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | access to local variable sink1 | -| GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | access to local variable sink10 | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | access to local variable sink11 | -| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | GlobalDataFlow.cs:415:22:415:35 | "taint source" : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | access to local variable sink19 | +| GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | access to local variable sink10 | +| GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | access to local variable sink11 | +| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | access to local variable sink19 | | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | access to local variable sink2 | -| GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | access to local variable sink20 | -| GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | access to local variable sink23 | +| GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | access to local variable sink20 | +| GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | access to local variable sink23 | | Capture.cs:12:19:12:24 | access to local variable sink27 | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:12:19:12:24 | access to local variable sink27 | access to local variable sink27 | | Capture.cs:21:23:21:28 | access to local variable sink28 | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:21:23:21:28 | access to local variable sink28 | access to local variable sink28 | | Capture.cs:30:19:30:24 | access to local variable sink29 | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:30:19:30:24 | access to local variable sink29 | access to local variable sink29 | @@ -390,20 +390,20 @@ nodes | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | access to local variable sink4 | | Capture.cs:122:15:122:20 | access to local variable sink40 | Capture.cs:115:26:115:39 | "taint source" : String | Capture.cs:122:15:122:20 | access to local variable sink40 | access to local variable sink40 | | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | access to local variable sink5 | -| GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | access to local variable sink6 | -| GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | GlobalDataFlow.cs:323:13:323:26 | "taint source" : String | GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | access to local variable sink7 | -| GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | GlobalDataFlow.cs:328:13:328:26 | "taint source" : String | GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | access to local variable sink8 | +| GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | access to local variable sink6 | +| GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | access to local variable sink7 | +| GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | access to local variable sink8 | | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | access to local variable sink9 | | Splitting.cs:11:19:11:19 | access to local variable x | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:11:19:11:19 | access to local variable x | access to local variable x | | Splitting.cs:34:19:34:19 | access to local variable x | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:34:19:34:19 | access to local variable x | access to local variable x | | Capture.cs:57:27:57:32 | access to parameter sink39 | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:57:27:57:32 | access to parameter sink39 | access to parameter sink39 | -| GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | | Splitting.cs:21:28:21:32 | access to parameter value | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:21:28:21:32 | access to parameter value | access to parameter value | | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | access to property SinkProperty0 | diff --git a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected index 586a0ef9ca8..2b712d5c2f8 100644 --- a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected +++ b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected @@ -54,25 +54,25 @@ | GlobalDataFlow.cs:78:9:78:46 | call to method ReturnRef | ref | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) | | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | return | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | yield return | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select | return | GlobalDataFlow.cs:82:22:82:95 | call to method Select | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select | yield return | GlobalDataFlow.cs:82:22:82:95 | call to method Select | -| GlobalDataFlow.cs:82:59:82:72 | call to method First | return | GlobalDataFlow.cs:82:59:82:72 | call to method First | -| GlobalDataFlow.cs:82:84:82:94 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip | return | GlobalDataFlow.cs:84:22:84:136 | call to method Zip | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip | yield return | GlobalDataFlow.cs:84:22:84:136 | call to method Zip | -| GlobalDataFlow.cs:84:59:84:72 | call to method First | return | GlobalDataFlow.cs:84:59:84:72 | call to method First | -| GlobalDataFlow.cs:84:125:84:135 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... | -| GlobalDataFlow.cs:86:22:86:136 | call to method Zip | return | GlobalDataFlow.cs:86:22:86:136 | call to method Zip | -| GlobalDataFlow.cs:86:22:86:136 | call to method Zip | yield return | GlobalDataFlow.cs:86:22:86:136 | call to method Zip | -| GlobalDataFlow.cs:86:106:86:119 | call to method First | return | GlobalDataFlow.cs:86:106:86:119 | call to method First | -| GlobalDataFlow.cs:86:125:86:135 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... | -| GlobalDataFlow.cs:88:22:88:70 | call to method Aggregate | return | GlobalDataFlow.cs:88:22:88:70 | call to method Aggregate | -| GlobalDataFlow.cs:88:43:88:61 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... | -| GlobalDataFlow.cs:88:64:88:69 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate | return | GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate | -| GlobalDataFlow.cs:90:75:90:88 | call to method First | return | GlobalDataFlow.cs:90:75:90:88 | call to method First | -| GlobalDataFlow.cs:90:91:90:109 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... | -| GlobalDataFlow.cs:90:112:90:117 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... | +| GlobalDataFlow.cs:80:22:80:93 | call to method First | return | GlobalDataFlow.cs:80:22:80:93 | call to method First | +| GlobalDataFlow.cs:82:22:82:87 | call to method Select | return | GlobalDataFlow.cs:82:22:82:87 | call to method Select | +| GlobalDataFlow.cs:82:22:82:87 | call to method Select | yield return | GlobalDataFlow.cs:82:22:82:87 | call to method Select | +| GlobalDataFlow.cs:82:22:82:95 | call to method First | return | GlobalDataFlow.cs:82:22:82:95 | call to method First | +| GlobalDataFlow.cs:82:76:82:86 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func | +| GlobalDataFlow.cs:84:22:84:128 | call to method Zip | return | GlobalDataFlow.cs:84:22:84:128 | call to method Zip | +| GlobalDataFlow.cs:84:22:84:128 | call to method Zip | yield return | GlobalDataFlow.cs:84:22:84:128 | call to method Zip | +| GlobalDataFlow.cs:84:22:84:136 | call to method First | return | GlobalDataFlow.cs:84:22:84:136 | call to method First | +| GlobalDataFlow.cs:84:117:84:127 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... | +| GlobalDataFlow.cs:86:22:86:128 | call to method Zip | return | GlobalDataFlow.cs:86:22:86:128 | call to method Zip | +| GlobalDataFlow.cs:86:22:86:128 | call to method Zip | yield return | GlobalDataFlow.cs:86:22:86:128 | call to method Zip | +| GlobalDataFlow.cs:86:22:86:136 | call to method First | return | GlobalDataFlow.cs:86:22:86:136 | call to method First | +| GlobalDataFlow.cs:86:117:86:127 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:86:117:86:127 | [output] (...) => ... | +| GlobalDataFlow.cs:88:22:88:110 | call to method Aggregate | return | GlobalDataFlow.cs:88:22:88:110 | call to method Aggregate | +| GlobalDataFlow.cs:88:83:88:101 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:88:83:88:101 | [output] (...) => ... | +| GlobalDataFlow.cs:88:104:88:109 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:88:104:88:109 | [output] (...) => ... | +| GlobalDataFlow.cs:90:22:90:110 | call to method Aggregate | return | GlobalDataFlow.cs:90:22:90:110 | call to method Aggregate | +| GlobalDataFlow.cs:90:83:90:101 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:90:83:90:101 | [output] (...) => ... | +| GlobalDataFlow.cs:90:104:90:109 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... | | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | out | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) | | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | ref | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) | | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | return | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | @@ -89,28 +89,30 @@ | GlobalDataFlow.cs:108:9:108:49 | call to method ReturnRef | ref | GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) | | GlobalDataFlow.cs:110:9:110:49 | call to method ReturnRef | out | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) | | GlobalDataFlow.cs:110:9:110:49 | call to method ReturnRef | ref | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven | return | GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven | yield return | GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven | +| GlobalDataFlow.cs:112:20:112:86 | call to method SelectEven | return | GlobalDataFlow.cs:112:20:112:86 | call to method SelectEven | +| GlobalDataFlow.cs:112:20:112:86 | call to method SelectEven | yield return | GlobalDataFlow.cs:112:20:112:86 | call to method SelectEven | +| GlobalDataFlow.cs:112:20:112:94 | call to method First | return | GlobalDataFlow.cs:112:20:112:94 | call to method First | | GlobalDataFlow.cs:114:20:114:82 | call to method Select | return | GlobalDataFlow.cs:114:20:114:82 | call to method Select | | GlobalDataFlow.cs:114:20:114:82 | call to method Select | yield return | GlobalDataFlow.cs:114:20:114:82 | call to method Select | +| GlobalDataFlow.cs:114:20:114:90 | call to method First | return | GlobalDataFlow.cs:114:20:114:90 | call to method First | | GlobalDataFlow.cs:114:76:114:81 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... | -| GlobalDataFlow.cs:116:20:116:134 | call to method Zip | return | GlobalDataFlow.cs:116:20:116:134 | call to method Zip | -| GlobalDataFlow.cs:116:20:116:134 | call to method Zip | yield return | GlobalDataFlow.cs:116:20:116:134 | call to method Zip | -| GlobalDataFlow.cs:116:57:116:70 | call to method First | return | GlobalDataFlow.cs:116:57:116:70 | call to method First | -| GlobalDataFlow.cs:116:123:116:133 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip | return | GlobalDataFlow.cs:118:20:118:134 | call to method Zip | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip | yield return | GlobalDataFlow.cs:118:20:118:134 | call to method Zip | -| GlobalDataFlow.cs:118:104:118:117 | call to method First | return | GlobalDataFlow.cs:118:104:118:117 | call to method First | -| GlobalDataFlow.cs:118:123:118:133 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... | -| GlobalDataFlow.cs:120:20:120:64 | call to method Aggregate | return | GlobalDataFlow.cs:120:20:120:64 | call to method Aggregate | -| GlobalDataFlow.cs:120:41:120:55 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... | -| GlobalDataFlow.cs:120:58:120:63 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... | -| GlobalDataFlow.cs:122:20:122:69 | call to method Aggregate | return | GlobalDataFlow.cs:122:20:122:69 | call to method Aggregate | -| GlobalDataFlow.cs:122:41:122:59 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:122:41:122:59 | [output] (...) => ... | -| GlobalDataFlow.cs:122:62:122:68 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:122:62:122:68 | [output] (...) => ... | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate | return | GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate | -| GlobalDataFlow.cs:124:46:124:58 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... | -| GlobalDataFlow.cs:124:61:124:66 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... | +| GlobalDataFlow.cs:116:20:116:126 | call to method Zip | return | GlobalDataFlow.cs:116:20:116:126 | call to method Zip | +| GlobalDataFlow.cs:116:20:116:126 | call to method Zip | yield return | GlobalDataFlow.cs:116:20:116:126 | call to method Zip | +| GlobalDataFlow.cs:116:20:116:134 | call to method First | return | GlobalDataFlow.cs:116:20:116:134 | call to method First | +| GlobalDataFlow.cs:116:115:116:125 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:116:115:116:125 | [output] (...) => ... | +| GlobalDataFlow.cs:118:20:118:126 | call to method Zip | return | GlobalDataFlow.cs:118:20:118:126 | call to method Zip | +| GlobalDataFlow.cs:118:20:118:126 | call to method Zip | yield return | GlobalDataFlow.cs:118:20:118:126 | call to method Zip | +| GlobalDataFlow.cs:118:20:118:134 | call to method First | return | GlobalDataFlow.cs:118:20:118:134 | call to method First | +| GlobalDataFlow.cs:118:115:118:125 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:118:115:118:125 | [output] (...) => ... | +| GlobalDataFlow.cs:120:20:120:104 | call to method Aggregate | return | GlobalDataFlow.cs:120:20:120:104 | call to method Aggregate | +| GlobalDataFlow.cs:120:81:120:95 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:120:81:120:95 | [output] (...) => ... | +| GlobalDataFlow.cs:120:98:120:103 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:120:98:120:103 | [output] (...) => ... | +| GlobalDataFlow.cs:122:20:122:109 | call to method Aggregate | return | GlobalDataFlow.cs:122:20:122:109 | call to method Aggregate | +| GlobalDataFlow.cs:122:81:122:99 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:122:81:122:99 | [output] (...) => ... | +| GlobalDataFlow.cs:122:102:122:108 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:122:102:122:108 | [output] (...) => ... | +| GlobalDataFlow.cs:124:20:124:107 | call to method Aggregate | return | GlobalDataFlow.cs:124:20:124:107 | call to method Aggregate | +| GlobalDataFlow.cs:124:86:124:98 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:124:86:124:98 | [output] (...) => ... | +| GlobalDataFlow.cs:124:101:124:106 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:124:101:124:106 | [output] (...) => ... | | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | out | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) | | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | ref | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) | | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | return | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | @@ -130,6 +132,7 @@ | GlobalDataFlow.cs:159:9:159:25 | call to method OutRef | ref | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) | | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | return | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | yield return | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | +| GlobalDataFlow.cs:161:22:161:39 | call to method First | return | GlobalDataFlow.cs:161:22:161:39 | call to method First | | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam | return | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam | | GlobalDataFlow.cs:167:20:167:27 | call to method NonOut | return | GlobalDataFlow.cs:167:20:167:27 | call to method NonOut | | GlobalDataFlow.cs:169:9:169:31 | call to method NonOutOut | out | GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) | @@ -150,32 +153,42 @@ | GlobalDataFlow.cs:193:37:193:42 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func | | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty | return | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty | | GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty | return | GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 | return | GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 | -| GlobalDataFlow.cs:210:22:210:39 | call to method Select | return | GlobalDataFlow.cs:210:22:210:39 | call to method Select | -| GlobalDataFlow.cs:210:22:210:39 | call to method Select | yield return | GlobalDataFlow.cs:210:22:210:39 | call to method Select | -| GlobalDataFlow.cs:210:37:210:38 | [implicit call] access to local variable f1 | return | GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 | +| GlobalDataFlow.cs:207:38:207:75 | call to method AsQueryable | return | GlobalDataFlow.cs:207:38:207:75 | call to method AsQueryable | +| GlobalDataFlow.cs:208:41:208:77 | call to method AsQueryable | return | GlobalDataFlow.cs:208:41:208:77 | call to method AsQueryable | +| GlobalDataFlow.cs:211:76:211:90 | call to method ReturnCheck2 | return | GlobalDataFlow.cs:211:76:211:90 | call to method ReturnCheck2 | | GlobalDataFlow.cs:212:22:212:39 | call to method Select | return | GlobalDataFlow.cs:212:22:212:39 | call to method Select | -| GlobalDataFlow.cs:212:37:212:38 | [implicit call] access to local variable f2 | return | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:214:22:214:49 | call to method Select | return | GlobalDataFlow.cs:214:22:214:49 | call to method Select | -| GlobalDataFlow.cs:214:22:214:49 | call to method Select | yield return | GlobalDataFlow.cs:214:22:214:49 | call to method Select | -| GlobalDataFlow.cs:214:37:214:48 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck | return | GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck | -| GlobalDataFlow.cs:220:23:220:43 | call to method Select | return | GlobalDataFlow.cs:220:23:220:43 | call to method Select | -| GlobalDataFlow.cs:220:23:220:43 | call to method Select | yield return | GlobalDataFlow.cs:220:23:220:43 | call to method Select | -| GlobalDataFlow.cs:220:41:220:42 | [implicit call] access to local variable f1 | return | GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 | -| GlobalDataFlow.cs:222:19:222:39 | call to method Select | return | GlobalDataFlow.cs:222:19:222:39 | call to method Select | -| GlobalDataFlow.cs:222:37:222:38 | [implicit call] access to local variable f2 | return | GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 | +| GlobalDataFlow.cs:212:22:212:39 | call to method Select | yield return | GlobalDataFlow.cs:212:22:212:39 | call to method Select | +| GlobalDataFlow.cs:212:22:212:47 | call to method First | return | GlobalDataFlow.cs:212:22:212:47 | call to method First | +| GlobalDataFlow.cs:212:37:212:38 | [implicit call] access to local variable f1 | return | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f1 | +| GlobalDataFlow.cs:214:22:214:39 | call to method Select | return | GlobalDataFlow.cs:214:22:214:39 | call to method Select | +| GlobalDataFlow.cs:214:22:214:47 | call to method First | return | GlobalDataFlow.cs:214:22:214:47 | call to method First | +| GlobalDataFlow.cs:214:37:214:38 | [implicit call] access to local variable f2 | return | GlobalDataFlow.cs:214:37:214:38 | [output] access to local variable f2 | +| GlobalDataFlow.cs:216:22:216:49 | call to method Select | return | GlobalDataFlow.cs:216:22:216:49 | call to method Select | +| GlobalDataFlow.cs:216:22:216:49 | call to method Select | yield return | GlobalDataFlow.cs:216:22:216:49 | call to method Select | +| GlobalDataFlow.cs:216:22:216:57 | call to method First | return | GlobalDataFlow.cs:216:22:216:57 | call to method First | +| GlobalDataFlow.cs:216:37:216:48 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:216:37:216:48 | [output] delegate creation of type Func | +| GlobalDataFlow.cs:221:76:221:92 | call to method NonReturnCheck | return | GlobalDataFlow.cs:221:76:221:92 | call to method NonReturnCheck | +| GlobalDataFlow.cs:222:23:222:43 | call to method Select | return | GlobalDataFlow.cs:222:23:222:43 | call to method Select | +| GlobalDataFlow.cs:222:23:222:43 | call to method Select | yield return | GlobalDataFlow.cs:222:23:222:43 | call to method Select | +| GlobalDataFlow.cs:222:23:222:51 | call to method First | return | GlobalDataFlow.cs:222:23:222:51 | call to method First | +| GlobalDataFlow.cs:222:41:222:42 | [implicit call] access to local variable f1 | return | GlobalDataFlow.cs:222:41:222:42 | [output] access to local variable f1 | | GlobalDataFlow.cs:224:19:224:39 | call to method Select | return | GlobalDataFlow.cs:224:19:224:39 | call to method Select | -| GlobalDataFlow.cs:224:19:224:39 | call to method Select | yield return | GlobalDataFlow.cs:224:19:224:39 | call to method Select | -| GlobalDataFlow.cs:224:37:224:38 | [implicit call] access to local variable f3 | return | GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 | +| GlobalDataFlow.cs:224:19:224:47 | call to method First | return | GlobalDataFlow.cs:224:19:224:47 | call to method First | +| GlobalDataFlow.cs:224:37:224:38 | [implicit call] access to local variable f2 | return | GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f2 | | GlobalDataFlow.cs:226:19:226:39 | call to method Select | return | GlobalDataFlow.cs:226:19:226:39 | call to method Select | -| GlobalDataFlow.cs:226:37:226:38 | [implicit call] access to local variable f4 | return | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 | -| GlobalDataFlow.cs:228:19:228:49 | call to method Select | return | GlobalDataFlow.cs:228:19:228:49 | call to method Select | -| GlobalDataFlow.cs:228:19:228:49 | call to method Select | yield return | GlobalDataFlow.cs:228:19:228:49 | call to method Select | -| GlobalDataFlow.cs:228:37:228:48 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | return | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call | return | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:431:44:431:47 | delegate call | return | GlobalDataFlow.cs:431:44:431:47 | delegate call | +| GlobalDataFlow.cs:226:19:226:39 | call to method Select | yield return | GlobalDataFlow.cs:226:19:226:39 | call to method Select | +| GlobalDataFlow.cs:226:19:226:47 | call to method First | return | GlobalDataFlow.cs:226:19:226:47 | call to method First | +| GlobalDataFlow.cs:226:37:226:38 | [implicit call] access to local variable f3 | return | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f3 | +| GlobalDataFlow.cs:228:19:228:39 | call to method Select | return | GlobalDataFlow.cs:228:19:228:39 | call to method Select | +| GlobalDataFlow.cs:228:19:228:47 | call to method First | return | GlobalDataFlow.cs:228:19:228:47 | call to method First | +| GlobalDataFlow.cs:228:37:228:38 | [implicit call] access to local variable f4 | return | GlobalDataFlow.cs:228:37:228:38 | [output] access to local variable f4 | +| GlobalDataFlow.cs:230:19:230:49 | call to method Select | return | GlobalDataFlow.cs:230:19:230:49 | call to method Select | +| GlobalDataFlow.cs:230:19:230:49 | call to method Select | yield return | GlobalDataFlow.cs:230:19:230:49 | call to method Select | +| GlobalDataFlow.cs:230:19:230:57 | call to method First | return | GlobalDataFlow.cs:230:19:230:57 | call to method First | +| GlobalDataFlow.cs:230:37:230:48 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:230:37:230:48 | [output] delegate creation of type Func | +| GlobalDataFlow.cs:279:17:279:38 | call to method ApplyFunc | return | GlobalDataFlow.cs:279:17:279:38 | call to method ApplyFunc | +| GlobalDataFlow.cs:368:16:368:19 | delegate call | return | GlobalDataFlow.cs:368:16:368:19 | delegate call | +| GlobalDataFlow.cs:433:44:433:47 | delegate call | return | GlobalDataFlow.cs:433:44:433:47 | delegate call | | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | return | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | return | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | | Splitting.cs:20:22:20:30 | call to method Return | return | Splitting.cs:20:22:20:30 | call to method Return | diff --git a/csharp/ql/test/library-tests/dataflow/global/GlobalDataFlow.cs b/csharp/ql/test/library-tests/dataflow/global/GlobalDataFlow.cs index 41630b7fd8f..83003aaea66 100644 --- a/csharp/ql/test/library-tests/dataflow/global/GlobalDataFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/global/GlobalDataFlow.cs @@ -77,17 +77,17 @@ public class DataFlow var sink3 = ""; ReturnRef(sink2, ref sink3, ref sink3); Check(sink3); - var sink13 = ((IEnumerable)new string[] { sink3 }).SelectEven(x => x); + var sink13 = ((IEnumerable)new string[] { sink3 }).SelectEven(x => x).First(); Check(sink13); - var sink14 = ((IEnumerable)new string[] { sink13.First() }).Select(ReturnCheck); + var sink14 = ((IEnumerable)new string[] { sink13 }).Select(ReturnCheck).First(); Check(sink14); - var sink15 = ((IEnumerable)new string[] { sink14.First() }).Zip(((IEnumerable)new string[] { "" }), (x, y) => x); + var sink15 = ((IEnumerable)new string[] { sink14 }).Zip(((IEnumerable)new string[] { "" }), (x, y) => x).First(); Check(sink15); - var sink16 = ((IEnumerable)new string[] { "" }).Zip(((IEnumerable)new string[] { sink15.First() }), (x, y) => y); + var sink16 = ((IEnumerable)new string[] { "" }).Zip(((IEnumerable)new string[] { sink15 }), (x, y) => y).First(); Check(sink16); - var sink17 = sink14.Aggregate("", (acc, s) => acc + s, x => x); + var sink17 = ((IEnumerable)new string[] { sink14 }).Aggregate("", (acc, s) => acc + s, x => x); Check(sink17); - var sink18 = ((IEnumerable)new string[] { "" }).Aggregate(sink14.First(), (acc, s) => acc + s, x => x); + var sink18 = ((IEnumerable)new string[] { "" }).Aggregate(sink14, (acc, s) => acc + s, x => x); Check(sink18); int sink21; Int32.TryParse(sink18, out sink21); @@ -109,19 +109,19 @@ public class DataFlow Check(nonSink0); ReturnRef(sink1, ref sink1, ref nonSink0); Check(nonSink0); - var nonSink1 = ((IEnumerable)new string[] { nonSink0 }).SelectEven(x => x); - Check(nonSink1); - nonSink1 = ((IEnumerable)new string[] { nonSink0 }).Select(x => x); - Check(nonSink1); - nonSink1 = ((IEnumerable)new string[] { sink14.First() }).Zip(((IEnumerable)new string[] { "" }), (x, y) => y); - Check(nonSink1); - nonSink1 = ((IEnumerable)new string[] { "" }).Zip(((IEnumerable)new string[] { sink15.First() }), (x, y) => x); - Check(nonSink1); - nonSink0 = sink14.Aggregate("", (acc, s) => acc, x => x); + nonSink0 = ((IEnumerable)new string[] { nonSink0 }).SelectEven(x => x).First(); Check(nonSink0); - nonSink0 = sink14.Aggregate("", (acc, s) => acc + s, x => ""); + nonSink0 = ((IEnumerable)new string[] { nonSink0 }).Select(x => x).First(); Check(nonSink0); - nonSink0 = nonSink1.Aggregate(sink1, (acc, s) => s, x => x); + nonSink0 = ((IEnumerable)new string[] { sink14 }).Zip(((IEnumerable)new string[] { "" }), (x, y) => y).First(); + Check(nonSink0); + nonSink0 = ((IEnumerable)new string[] { "" }).Zip(((IEnumerable)new string[] { sink15 }), (x, y) => x).First(); + Check(nonSink0); + nonSink0 = ((IEnumerable)new string[] { sink14 }).Aggregate("", (acc, s) => acc, x => x); + Check(nonSink0); + nonSink0 = ((IEnumerable)new string[] { sink14 }).Aggregate("", (acc, s) => acc + s, x => ""); + Check(nonSink0); + nonSink0 = ((IEnumerable)new string[] { nonSink0 }).Aggregate(sink1, (acc, s) => s, x => x); Check(nonSink0); int nonSink2; Int32.TryParse(nonSink0, out nonSink2); @@ -158,7 +158,7 @@ public class DataFlow var sink8 = ""; OutRef(ref sink8); Check(sink8); - var sink12 = OutYield(); + var sink12 = OutYield().First(); Check(sink12); var sink23 = TaintedParam(nonSink0); // even though the argument is not tainted, the parameter is considered tainted Check(sink23); @@ -202,30 +202,32 @@ public class DataFlow Check(nonSink0); } - public void M2(IQueryable tainted, IQueryable notTainted) + public void M2() { + IQueryable tainted = new[] { "taint source" }.AsQueryable(); + IQueryable notTainted = new[] { "not tainted" }.AsQueryable(); // Flow into a callable via library call, tainted Func f1 = sinkParam10 => { Check(sinkParam10); return sinkParam10; }; System.Linq.Expressions.Expression> f2 = x => ReturnCheck2(x); - var sink24 = tainted.Select(f1); + var sink24 = tainted.Select(f1).First(); Check(sink24); - var sink25 = tainted.Select(f2); + var sink25 = tainted.Select(f2).First(); Check(sink25); - var sink26 = tainted.Select(ReturnCheck3); + var sink26 = tainted.Select(ReturnCheck3).First(); Check(sink26); // Flow into a callable via library call, not tainted Func f3 = nonSinkParam => { Check(nonSinkParam); return nonSinkParam; }; System.Linq.Expressions.Expression> f4 = x => NonReturnCheck(x); - var nonSink = notTainted.Select(f1); + var nonSink = notTainted.Select(f1).First(); Check(nonSink); - nonSink = notTainted.Select(f2); + nonSink = notTainted.Select(f2).First(); Check(nonSink); - nonSink = notTainted.Select(f3); + nonSink = notTainted.Select(f3).First(); Check(nonSink); - nonSink = notTainted.Select(f4); + nonSink = notTainted.Select(f4).First(); Check(nonSink); - nonSink = notTainted.Select(ReturnCheck3); + nonSink = notTainted.Select(ReturnCheck3).First(); Check(nonSink); } diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected index 10d873cc2fc..57fd2c9e0c3 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected @@ -37,22 +37,22 @@ | 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:208:58:208:68 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 | -| GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 | -| GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 | -| 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:294:15:294:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | +| GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | +| GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | +| GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | +| GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | +| GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:296:15:296:24 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:302:15:302:24 | access to parameter sinkParam9 | +| GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | +| GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | +| GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | | 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/TaintTrackingEdges.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingEdges.expected deleted file mode 100644 index bd9d777b9dd..00000000000 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingEdges.expected +++ /dev/null @@ -1,5782 +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 : Object | Capture.cs:7:20:7:26 | tainted | -| Capture.cs:7:20:7:26 | tainted : Object | Capture.cs:7:20:7:26 | tainted : String | -| Capture.cs:7:20:7:26 | tainted : Object | Capture.cs:14:9:14:20 | [implicit argument] tainted | -| Capture.cs:7:20:7:26 | tainted : Object | Capture.cs:14:9:14:20 | [implicit argument] tainted : String | -| Capture.cs:7:20:7:26 | tainted : Object | Capture.cs:25:9:25:20 | [implicit argument] tainted | -| Capture.cs:7:20:7:26 | tainted : Object | Capture.cs:25:9:25:20 | [implicit argument] tainted : String | -| Capture.cs:7:20:7:26 | tainted : Object | Capture.cs:33:9:33:40 | [implicit argument] tainted | -| Capture.cs:7:20:7:26 | tainted : Object | Capture.cs:33:9:33:40 | [implicit argument] tainted : String | -| Capture.cs:7:20:7:26 | tainted : Object | Capture.cs:61:36:61:42 | access to parameter tainted | -| Capture.cs:7:20:7:26 | tainted : Object | Capture.cs:61:36:61:42 | access to parameter tainted : String | -| 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 : Object | Capture.cs:27:43:27:45 | arg | -| Capture.cs:27:43:27:45 | arg : Object | Capture.cs:27:43:27:45 | arg : String | -| Capture.cs:27:43:27:45 | arg : Object | Capture.cs:31:20:31:22 | access to parameter arg | -| Capture.cs:27:43:27:45 | arg : Object | Capture.cs:31:20:31:22 | access to parameter arg : String | -| 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 | -| Capture.cs:27:43:27:45 | arg : String | Capture.cs:31:20:31:22 | access to parameter arg : String | -| Capture.cs:27:43:27:45 | arg : String | Capture.cs:31:20:31:22 | access to parameter arg : String | -| Capture.cs:27:43:27:45 | arg : String[] | Capture.cs:27:43:27:45 | arg | -| Capture.cs:27:43:27:45 | arg : String[] | Capture.cs:27:43:27:45 | arg : String | -| 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:21 | array creation of type String[] : String[] | Capture.cs:33:30:33:39 | [output] access to local variable captureIn3 | -| Capture.cs:33:9:33:21 | array creation of type String[] : String[] | Capture.cs:33:30:33:39 | [output] access to local variable captureIn3 : 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:33:9:33:40 | call to method Select : IEnumerable | Capture.cs:33:9:33:50 | call to method ToArray | -| Capture.cs:33:9:33:40 | call to method Select : IEnumerable | Capture.cs:33:9:33:50 | call to method ToArray : String[] | -| Capture.cs:33:17:33:19 | " " : String | Capture.cs:33:9:33:21 | array creation of type String[] | -| Capture.cs:33:17:33:19 | " " : String | Capture.cs:33:9:33:21 | array creation of type String[] : String[] | -| Capture.cs:33:30:33:39 | [output] access to local variable captureIn3 : String | Capture.cs:33:9:33:40 | call to method Select | -| Capture.cs:33:30:33:39 | [output] access to local variable captureIn3 : String | Capture.cs:33:9:33:40 | call to method Select : IEnumerable | -| Capture.cs:33:30:33:39 | [output] access to local variable captureIn3 : String | Capture.cs:33:9:33:50 | call to method ToArray | -| Capture.cs:33:30:33:39 | [output] access to local variable captureIn3 : String | Capture.cs:33:9:33:50 | call to method ToArray : 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 : Object | Capture.cs:50:33:50:40 | nonSink0 | -| Capture.cs:50:33:50:40 | nonSink0 : Object | Capture.cs:50:33:50:40 | nonSink0 : String | -| Capture.cs:50:33:50:40 | nonSink0 : Object | Capture.cs:52:13:59:14 | [implicit argument] nonSink0 | -| Capture.cs:50:33:50:40 | nonSink0 : Object | 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 | -| 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 : Object | Capture.cs:50:50:50:55 | sink39 | -| Capture.cs:50:50:50:55 | sink39 : Object | Capture.cs:50:50:50:55 | sink39 : String | -| Capture.cs:50:50:50:55 | sink39 : Object | Capture.cs:52:13:59:14 | [implicit argument] sink39 | -| Capture.cs:50:50:50:55 | sink39 : Object | 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 | -| 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 : Object | Capture.cs:87:44:87:46 | arg | -| Capture.cs:87:44:87:46 | arg : Object | Capture.cs:87:44:87:46 | arg : String | -| Capture.cs:87:44:87:46 | arg : Object | Capture.cs:90:20:90:22 | access to parameter arg | -| Capture.cs:87:44:87:46 | arg : Object | Capture.cs:90:20:90:22 | access to parameter arg : String | -| 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 | -| Capture.cs:87:44:87:46 | arg : String | Capture.cs:90:20:90:22 | access to parameter arg : String | -| Capture.cs:87:44:87:46 | arg : String | Capture.cs:90:20:90:22 | access to parameter arg : String | -| Capture.cs:87:44:87:46 | arg : String[] | Capture.cs:87:44:87:46 | arg | -| Capture.cs:87:44:87:46 | arg : String[] | Capture.cs:87:44:87:46 | arg : String | -| 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:21 | array creation of type String[] : String[] | Capture.cs:92:30:92:40 | [output] access to local variable captureOut3 | -| Capture.cs:92:9:92:21 | array creation of type String[] : String[] | Capture.cs:92:30:92:40 | [output] access to local variable captureOut3 : 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:92:9:92:41 | call to method Select : IEnumerable | Capture.cs:92:9:92:51 | call to method ToArray | -| Capture.cs:92:9:92:41 | call to method Select : IEnumerable | Capture.cs:92:9:92:51 | call to method ToArray : String[] | -| Capture.cs:92:17:92:19 | " " : String | Capture.cs:92:9:92:21 | array creation of type String[] | -| Capture.cs:92:17:92:19 | " " : String | Capture.cs:92:9:92:21 | array creation of type String[] : String[] | -| Capture.cs:92:30:92:40 | [output] access to local variable captureOut3 : String | Capture.cs:92:9:92:41 | call to method Select | -| Capture.cs:92:30:92:40 | [output] access to local variable captureOut3 : String | Capture.cs:92:9:92:41 | call to method Select : IEnumerable | -| Capture.cs:92:30:92:40 | [output] access to local variable captureOut3 : String | Capture.cs:92:9:92:51 | call to method ToArray | -| Capture.cs:92:30:92:40 | [output] access to local variable captureOut3 : String | Capture.cs:92:9:92:51 | call to method ToArray : 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 : Object | Capture.cs:125:25:125:31 | tainted | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:125:25:125:31 | tainted : String | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:132:9:132:25 | [implicit argument] tainted | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:132:9:132:25 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:144:9:144:25 | [implicit argument] tainted | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:144:9:144:25 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:153:9:153:45 | [implicit argument] tainted | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:153:9:153:45 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:160:22:160:38 | [implicit argument] tainted | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:160:22:160:38 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:168:25:168:31 | access to parameter tainted | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:168:25:168:31 | access to parameter tainted : String | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:194:25:194:31 | access to parameter tainted | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:194:25:194:31 | access to parameter tainted : String | -| 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 : Object | Capture.cs:148:48:148:50 | arg | -| Capture.cs:148:48:148:50 | arg : Object | Capture.cs:148:48:148:50 | arg : String | -| Capture.cs:148:48:148:50 | arg : Object | Capture.cs:151:20:151:22 | access to parameter arg | -| Capture.cs:148:48:148:50 | arg : Object | Capture.cs:151:20:151:22 | access to parameter arg : String | -| 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 | -| Capture.cs:148:48:148:50 | arg : String | Capture.cs:151:20:151:22 | access to parameter arg : String | -| Capture.cs:148:48:148:50 | arg : String | Capture.cs:151:20:151:22 | access to parameter arg : String | -| Capture.cs:148:48:148:50 | arg : String[] | Capture.cs:148:48:148:50 | arg | -| Capture.cs:148:48:148:50 | arg : String[] | Capture.cs:148:48:148:50 | arg : String | -| 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:21 | array creation of type String[] : String[] | Capture.cs:153:30:153:44 | [output] access to local variable captureThrough3 | -| Capture.cs:153:9:153:21 | array creation of type String[] : String[] | Capture.cs:153:30:153:44 | [output] access to local variable captureThrough3 : 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:153:9:153:45 | call to method Select : IEnumerable | Capture.cs:153:9:153:55 | call to method ToArray | -| Capture.cs:153:9:153:45 | call to method Select : IEnumerable | Capture.cs:153:9:153:55 | call to method ToArray : String[] | -| Capture.cs:153:17:153:19 | " " : String | Capture.cs:153:9:153:21 | array creation of type String[] | -| Capture.cs:153:17:153:19 | " " : String | Capture.cs:153:9:153:21 | array creation of type String[] : String[] | -| Capture.cs:153:30:153:44 | [output] access to local variable captureThrough3 : String | Capture.cs:153:9:153:45 | call to method Select | -| Capture.cs:153:30:153:44 | [output] access to local variable captureThrough3 : String | Capture.cs:153:9:153:45 | call to method Select : IEnumerable | -| Capture.cs:153:30:153:44 | [output] access to local variable captureThrough3 : String | Capture.cs:153:9:153:55 | call to method ToArray | -| Capture.cs:153:30:153:44 | [output] access to local variable captureThrough3 : String | Capture.cs:153:9:153:55 | call to method ToArray : 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 : Object | Capture.cs:164:37:164:37 | p | -| Capture.cs:164:37:164:37 | p : Object | Capture.cs:164:37:164:37 | p : String | -| Capture.cs:164:37:164:37 | p : Object | Capture.cs:166:13:166:22 | SSA def(sink37) | -| Capture.cs:164:37:164:37 | p : Object | Capture.cs:166:13:166:22 | SSA def(sink37) : String | -| Capture.cs:164:37:164:37 | p : Object | Capture.cs:166:22:166:22 | access to parameter p | -| Capture.cs:164:37:164:37 | p : Object | Capture.cs:166:22:166:22 | access to parameter p : 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 : Object | Capture.cs:188:26:188:26 | s | -| Capture.cs:188:26:188:26 | s : Object | Capture.cs:188:26:188:26 | s : String | -| Capture.cs:188:26:188:26 | s : Object | Capture.cs:191:20:191:22 | [implicit argument] s | -| Capture.cs:188:26:188:26 | s : Object | 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 | -| 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 | -| Capture.cs:202:34:202:34 | a : Object | Capture.cs:202:34:202:34 | a | -| Capture.cs:202:34:202:34 | a : Object | Capture.cs:202:34:202:34 | a : Action | -| Capture.cs:202:34:202:34 | a : Object | Capture.cs:204:9:204:9 | access to parameter a | -| Capture.cs:202:34:202:34 | a : Object | 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:13:37:54 | SSA def(args) | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) : Object[] | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | -| 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:38:33:38:36 | access to local variable args | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:38:33:38:36 | access to local variable args : Object[] | -| 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:13:37:54 | SSA def(args) | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) : Object[] | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | -| 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:38:33:38:36 | access to local variable args | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:38:33:38:36 | access to local variable args : Object[] | -| 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:13:37:54 | SSA def(args) | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) : Object[] | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | -| 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:38:33:38:36 | access to local variable args | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:38:33:38:36 | access to local variable args : Object[] | -| 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:13:37:54 | SSA def(args) | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) : Object[] | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | -| 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:38:33:38:36 | access to local variable args | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:38:33:38:36 | access to local variable args : Object[] | -| 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:13:37:54 | SSA def(args) | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) : Object[] | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | -| 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:38:33:38:36 | access to local variable args | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:38:33:38:36 | access to local variable args : Object[] | -| 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:13:37:54 | SSA def(args) | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) : Object[] | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | -| 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:38:33:38:36 | access to local variable args | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:38:33:38:36 | access to local variable args : Object[] | -| 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:13:37:54 | SSA def(args) | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) : Object[] | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | -| 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:38:33:38:36 | access to local variable args | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:38:33:38:36 | access to local variable args : Object[] | -| 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:37:13:37:54 | SSA def(args) | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) : Object[] | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:38:33:38:36 | access to local variable args | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | 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 : Object | GlobalDataFlow.cs:44:30:44:39 | sinkParam2 | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : Object | GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : Object | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : Object | 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 | -| 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 : Object | GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 | -| GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 : Object | GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 : String | -| GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 : Object | GlobalDataFlow.cs:48:56:48:68 | access to parameter nonSinkParam1 | -| GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 : Object | 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 | -| 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 | GlobalDataFlow.cs:48:24:48:69 | SSA def(nonIn1) | -| GlobalDataFlow.cs:48:33:48:69 | (...) => ... : Action | GlobalDataFlow.cs:48:24:48:69 | SSA def(nonIn1) : Action | -| GlobalDataFlow.cs:48:33:48:69 | (...) => ... : Action | GlobalDataFlow.cs:49:9:49:14 | access to local variable nonIn1 | -| GlobalDataFlow.cs:48:33:48:69 | (...) => ... : Action | GlobalDataFlow.cs:49:9:49:14 | access to local variable nonIn1 : Action | -| GlobalDataFlow.cs:49:16:49:17 | "" : String | GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 | -| GlobalDataFlow.cs:49:16:49:17 | "" : String | GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 : String | -| GlobalDataFlow.cs:52:15:52:17 | delegate creation of type Action : Action | GlobalDataFlow.cs:359:36:359:36 | a | -| GlobalDataFlow.cs:52:15:52:17 | delegate creation of type Action : Action | GlobalDataFlow.cs:359:36:359:36 | a : Action | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:359:41:359:41 | x | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:359:41:359:41 | x : String | -| GlobalDataFlow.cs:53:15:53:15 | x : Object | GlobalDataFlow.cs:53:15:53:15 | x | -| GlobalDataFlow.cs:53:15:53:15 | x : Object | GlobalDataFlow.cs:53:15:53:15 | x : String | -| GlobalDataFlow.cs:53:15:53:15 | x : Object | GlobalDataFlow.cs:53:24:53:24 | access to parameter x | -| GlobalDataFlow.cs:53:15:53:15 | x : Object | GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | -| GlobalDataFlow.cs:53:15:53:15 | x : String | GlobalDataFlow.cs:53:24:53:24 | access to parameter x | -| GlobalDataFlow.cs:53:15:53:15 | x : String | GlobalDataFlow.cs:53:24:53:24 | access to parameter x | -| GlobalDataFlow.cs:53:15:53:15 | x : String | GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | -| GlobalDataFlow.cs:53:15:53:15 | x : String | GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | -| GlobalDataFlow.cs:53:15:53:15 | x : T | GlobalDataFlow.cs:53:24:53:24 | access to parameter x | -| GlobalDataFlow.cs:53:15:53:15 | x : T | GlobalDataFlow.cs:53:24:53:24 | access to parameter x : T | -| GlobalDataFlow.cs:53:15:53:25 | (...) => ... : Action | GlobalDataFlow.cs:359:36:359:36 | a | -| GlobalDataFlow.cs:53:15:53:25 | (...) => ... : Action | GlobalDataFlow.cs:359:36:359:36 | a : Action | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : T | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : T | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : T | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:359:41:359:41 | x | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:359:41:359:41 | x : String | -| GlobalDataFlow.cs:54:23:54:41 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a | -| GlobalDataFlow.cs:54:23:54:41 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:373:52:373:52 | x | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:373:52:373:52 | x : String | -| GlobalDataFlow.cs:55:23:55:25 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a | -| GlobalDataFlow.cs:55:23:55:25 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:373:52:373:52 | x | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:373:52:373:52 | x : String | -| GlobalDataFlow.cs:56:9:56:48 | SSA def(DataFlow.myDelegate) : MyDelegate | GlobalDataFlow.cs:57:23:57:32 | access to field myDelegate | -| GlobalDataFlow.cs:56:9:56:48 | SSA def(DataFlow.myDelegate) : MyDelegate | GlobalDataFlow.cs:57:23:57:32 | access to field myDelegate : MyDelegate | -| GlobalDataFlow.cs:56:22:56:48 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:56:9:56:48 | SSA def(DataFlow.myDelegate) | -| GlobalDataFlow.cs:56:22:56:48 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:56:9:56:48 | SSA def(DataFlow.myDelegate) : MyDelegate | -| GlobalDataFlow.cs:56:22:56:48 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:57:23:57:32 | access to field myDelegate | -| GlobalDataFlow.cs:56:22:56:48 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:57:23:57:32 | access to field myDelegate : MyDelegate | -| GlobalDataFlow.cs:56:37:56:37 | x : Object | GlobalDataFlow.cs:56:37:56:37 | x | -| GlobalDataFlow.cs:56:37:56:37 | x : Object | GlobalDataFlow.cs:56:37:56:37 | x : String | -| GlobalDataFlow.cs:56:37:56:37 | x : Object | GlobalDataFlow.cs:56:46:56:46 | access to parameter x | -| GlobalDataFlow.cs:56:37:56:37 | x : Object | GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | -| GlobalDataFlow.cs:56:37:56:37 | x : String | GlobalDataFlow.cs:56:46:56:46 | access to parameter x | -| GlobalDataFlow.cs:56:37:56:37 | x : String | GlobalDataFlow.cs:56:46:56:46 | access to parameter x | -| GlobalDataFlow.cs:56:37:56:37 | x : String | GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | -| GlobalDataFlow.cs:56:37:56:37 | x : String | GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | GlobalDataFlow.cs:265:26:265:35 | sinkParam7 | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | GlobalDataFlow.cs:265:26:265:35 | sinkParam7 | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | -| GlobalDataFlow.cs:57:23:57:32 | access to field myDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a | -| GlobalDataFlow.cs:57:23:57:32 | access to field myDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:373:52:373:52 | x | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:373:52:373:52 | x : String | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : Object | GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : Object | GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : String | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : Object | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : Object | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 : String | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : String | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : String | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : String | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 : String | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : String | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 : String | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : T | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : T | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 : T | -| GlobalDataFlow.cs:60:15:60:51 | (...) => ... : Action | GlobalDataFlow.cs:359:36:359:36 | a | -| GlobalDataFlow.cs:60:15:60:51 | (...) => ... : Action | GlobalDataFlow.cs:359:36:359:36 | a : Action | -| GlobalDataFlow.cs:60:54:60:66 | "not tainted" : String | GlobalDataFlow.cs:359:41:359:41 | x | -| GlobalDataFlow.cs:60:54:60:66 | "not tainted" : String | GlobalDataFlow.cs:359:41:359:41 | x : String | -| GlobalDataFlow.cs:61:23:61:75 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a | -| GlobalDataFlow.cs:61:23:61:75 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | -| GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : Object | GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 | -| GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : Object | GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | -| GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : Object | GlobalDataFlow.cs:61:61:61:73 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : Object | GlobalDataFlow.cs:61:61:61:73 | access to parameter nonSinkParam0 : String | -| GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | GlobalDataFlow.cs:61:61:61:73 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | GlobalDataFlow.cs:61:61:61:73 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | GlobalDataFlow.cs:61:61:61:73 | access to parameter nonSinkParam0 : String | -| GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | GlobalDataFlow.cs:61:61:61:73 | access to parameter nonSinkParam0 : String | -| GlobalDataFlow.cs:61:78:61:90 | "not tainted" : String | GlobalDataFlow.cs:373:52:373:52 | x | -| GlobalDataFlow.cs:61:78:61:90 | "not tainted" : String | GlobalDataFlow.cs:373:52:373:52 | x : String | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:67:9:67:21 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:153:21:153:25 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:404:9:404:11 | this | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:404:9:404:11 | this : DataFlow | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:404:9:404:11 | value | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:404:9:404:11 | value : String | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:153:21:153:25 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:410:9:410:11 | this | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:410:9:410:11 | this : DataFlow | -| GlobalDataFlow.cs:67:25:67:37 | "not tainted" : String | GlobalDataFlow.cs:410:9:410:11 | value | -| GlobalDataFlow.cs:67:25:67:37 | "not tainted" : String | GlobalDataFlow.cs:410:9:410:11 | value : String | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : String | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : String | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : String | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : T | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : T | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : T | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : T | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : T | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : T | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : T | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : String | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : String | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : T | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : T | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:21:70:46 | call to method Return | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : String | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : String | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : T | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : T | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : T | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : T | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : Object | GlobalDataFlow.cs:72:21:72:101 | (...) ... | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : Object | GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | GlobalDataFlow.cs:72:21:72:101 | (...) ... | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : T | GlobalDataFlow.cs:72:21:72:101 | (...) ... | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : T | GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : T | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | GlobalDataFlow.cs:275:26:275:26 | x : T | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : String | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : T | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : Object | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:281:32:281:32 | x : Object | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : String | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:281:32:281:32 | x : String | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : T | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : T | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:281:32:281:32 | x : T | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : Object | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : Object | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : Object | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : Object | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : Object | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : Object | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : String | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : T | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : T | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : T | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : T | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : T | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : T | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : Object | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : Object | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : Object | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : String | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : String | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : T | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : T | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : T | -| GlobalDataFlow.cs:77:13:77:22 | SSA def(sink3) : String | GlobalDataFlow.cs:78:30:78:34 | access to local variable sink3 | -| GlobalDataFlow.cs:77:13:77:22 | SSA def(sink3) : String | GlobalDataFlow.cs:78:30:78:34 | access to local variable sink3 : String | -| GlobalDataFlow.cs:77:13:77:22 | SSA def(sink3) : String | GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 | -| GlobalDataFlow.cs:77:13:77:22 | SSA def(sink3) : String | GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 : String | -| GlobalDataFlow.cs:77:21:77:22 | "" : String | GlobalDataFlow.cs:77:13:77:22 | SSA def(sink3) | -| GlobalDataFlow.cs:77:21:77:22 | "" : String | GlobalDataFlow.cs:77:13:77:22 | SSA def(sink3) : String | -| GlobalDataFlow.cs:77:21:77:22 | "" : String | GlobalDataFlow.cs:78:30:78:34 | access to local variable sink3 | -| GlobalDataFlow.cs:77:21:77:22 | "" : String | GlobalDataFlow.cs:78:30:78:34 | access to local variable sink3 : String | -| GlobalDataFlow.cs:77:21:77:22 | "" : String | GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 | -| GlobalDataFlow.cs:77:21:77:22 | "" : String | GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 : String | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : Object | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : Object | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : Object | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : Object | GlobalDataFlow.cs:287:32:287:32 | x : Object | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | GlobalDataFlow.cs:287:32:287:32 | x : String | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : T | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : T | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : T | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : T | GlobalDataFlow.cs:287:32:287:32 | x : T | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | -| GlobalDataFlow.cs:78:30:78:34 | access to local variable sink3 : String | GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | access to local variable sink3 : String | GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 : String | -| GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 : String | GlobalDataFlow.cs:287:50:287:50 | z | -| GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 : String | GlobalDataFlow.cs:287:50:287:50 | z : String | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First : String | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First : String | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First : String | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First : String | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable | GlobalDataFlow.cs:426:71:426:71 | e | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable | GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | GlobalDataFlow.cs:426:71:426:71 | e | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | GlobalDataFlow.cs:426:71:426:71 | e : String[] | -| GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | GlobalDataFlow.cs:80:23:80:65 | (...) ... | -| GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | -| GlobalDataFlow.cs:80:79:80:79 | x : Object | GlobalDataFlow.cs:80:79:80:79 | x | -| GlobalDataFlow.cs:80:79:80:79 | x : Object | GlobalDataFlow.cs:80:79:80:79 | x : String | -| GlobalDataFlow.cs:80:79:80:79 | x : Object | GlobalDataFlow.cs:80:84:80:84 | access to parameter x | -| GlobalDataFlow.cs:80:79:80:79 | x : Object | GlobalDataFlow.cs:80:84:80:84 | access to parameter x : String | -| GlobalDataFlow.cs:80:79:80:79 | x : String | GlobalDataFlow.cs:80:84:80:84 | access to parameter x | -| GlobalDataFlow.cs:80:79:80:79 | x : String | GlobalDataFlow.cs:80:84:80:84 | access to parameter x : String | -| GlobalDataFlow.cs:80:79:80:79 | x : T | GlobalDataFlow.cs:80:84:80:84 | access to parameter x | -| GlobalDataFlow.cs:80:79:80:79 | x : T | GlobalDataFlow.cs:80:84:80:84 | access to parameter x : T | -| GlobalDataFlow.cs:80:79:80:84 | (...) => ... : Func | GlobalDataFlow.cs:426:85:426:85 | f | -| GlobalDataFlow.cs:80:79:80:84 | (...) => ... : Func | GlobalDataFlow.cs:426:85:426:85 | f : Func | -| GlobalDataFlow.cs:80:84:80:84 | access to parameter x : String | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:80:84:80:84 | access to parameter x : String | GlobalDataFlow.cs:431:44:431:47 | delegate call : String | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First : String | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First : String | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:84:23:84:74 | (...) ... | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:84:59:84:72 | call to method First | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:84:59:84:72 | call to method First : String | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:90:75:90:88 | call to method First | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:90:75:90:88 | call to method First : String | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First : String | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:84:23:84:74 | (...) ... | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:84:59:84:72 | call to method First | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:84:59:84:72 | call to method First : String | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:90:75:90:88 | call to method First | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:90:75:90:88 | call to method First : String | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First : String | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable | GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable | GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : IEnumerable | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | -| GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | GlobalDataFlow.cs:82:23:82:74 | (...) ... | -| GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | -| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... | -| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | -| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] | -| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First | -| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First : String | -| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... | -| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | -| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] | -| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First | -| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First : String | -| GlobalDataFlow.cs:82:59:82:72 | call to method First : String | GlobalDataFlow.cs:82:23:82:74 | (...) ... | -| GlobalDataFlow.cs:82:59:82:72 | call to method First : String | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | -| GlobalDataFlow.cs:82:59:82:72 | call to method First : String | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] | -| GlobalDataFlow.cs:82:59:82:72 | call to method First : String | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:82:22:82:95 | call to method Select | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:84:23:84:74 | (...) ... | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:84:59:84:72 | call to method First | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:84:59:84:72 | call to method First : String | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:90:75:90:88 | call to method First | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:90:75:90:88 | call to method First : String | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:116:21:116:72 | (...) ... | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:116:57:116:70 | call to method First | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:116:57:116:70 | call to method First : String | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:82:22:82:95 | call to method Select | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:84:23:84:74 | (...) ... | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:84:59:84:72 | call to method First | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:84:59:84:72 | call to method First : String | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:90:75:90:88 | call to method First | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:90:75:90:88 | call to method First : String | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:116:21:116:72 | (...) ... | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:116:57:116:70 | call to method First | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:116:57:116:70 | call to method First : String | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:23:84:74 | (...) ... | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:59:84:72 | call to method First | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:59:84:72 | call to method First : String | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:88 | call to method First | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:88 | call to method First : String | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First : String | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:86:70:86:121 | (...) ... | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:86:106:86:119 | call to method First | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:86:106:86:119 | call to method First : String | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:118:68:118:119 | (...) ... | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:118:104:118:117 | call to method First | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:118:104:118:117 | call to method First : String | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:70:86:121 | (...) ... | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:106:86:119 | call to method First | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:106:86:119 | call to method First : String | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:68:118:119 | (...) ... | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:104:118:117 | call to method First | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:104:118:117 | call to method First : String | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable | GlobalDataFlow.cs:84:126:84:126 | x | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable | GlobalDataFlow.cs:84:126:84:126 | x : IEnumerable | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | GlobalDataFlow.cs:84:126:84:126 | x | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | GlobalDataFlow.cs:84:126:84:126 | x : String[] | -| GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | GlobalDataFlow.cs:84:23:84:74 | (...) ... | -| GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:23:84:74 | (...) ... | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:59:84:72 | call to method First | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:59:84:72 | call to method First : String | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:88 | call to method First | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:88 | call to method First : String | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First : String | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:84:59:84:72 | call to method First : String | GlobalDataFlow.cs:84:23:84:74 | (...) ... | -| GlobalDataFlow.cs:84:59:84:72 | call to method First : String | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | -| GlobalDataFlow.cs:84:59:84:72 | call to method First : String | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] | -| GlobalDataFlow.cs:84:59:84:72 | call to method First : String | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:84:103:84:121 | array creation of type String[] : String[] | GlobalDataFlow.cs:84:82:84:121 | (...) ... | -| GlobalDataFlow.cs:84:103:84:121 | array creation of type String[] : String[] | GlobalDataFlow.cs:84:82:84:121 | (...) ... : String[] | -| GlobalDataFlow.cs:84:118:84:119 | "" : String | GlobalDataFlow.cs:84:82:84:121 | (...) ... | -| GlobalDataFlow.cs:84:118:84:119 | "" : String | GlobalDataFlow.cs:84:82:84:121 | (...) ... : String[] | -| GlobalDataFlow.cs:84:118:84:119 | "" : String | GlobalDataFlow.cs:84:103:84:121 | array creation of type String[] | -| GlobalDataFlow.cs:84:118:84:119 | "" : String | GlobalDataFlow.cs:84:103:84:121 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:84:22:84:136 | call to method Zip | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:106:86:119 | call to method First | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:106:86:119 | call to method First : String | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:68:118:119 | (...) ... | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:104:118:117 | call to method First | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:104:118:117 | call to method First : String | -| GlobalDataFlow.cs:84:126:84:126 | x : IEnumerable | GlobalDataFlow.cs:84:126:84:126 | x | -| GlobalDataFlow.cs:84:126:84:126 | x : IEnumerable | GlobalDataFlow.cs:84:126:84:126 | x : String | -| GlobalDataFlow.cs:84:126:84:126 | x : IEnumerable | GlobalDataFlow.cs:84:135:84:135 | access to parameter x | -| GlobalDataFlow.cs:84:126:84:126 | x : IEnumerable | GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | -| GlobalDataFlow.cs:84:126:84:126 | x : Object | GlobalDataFlow.cs:84:126:84:126 | x | -| GlobalDataFlow.cs:84:126:84:126 | x : Object | GlobalDataFlow.cs:84:126:84:126 | x : String | -| GlobalDataFlow.cs:84:126:84:126 | x : Object | GlobalDataFlow.cs:84:135:84:135 | access to parameter x | -| GlobalDataFlow.cs:84:126:84:126 | x : Object | GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | -| GlobalDataFlow.cs:84:126:84:126 | x : String | GlobalDataFlow.cs:84:135:84:135 | access to parameter x | -| GlobalDataFlow.cs:84:126:84:126 | x : String | GlobalDataFlow.cs:84:135:84:135 | access to parameter x | -| GlobalDataFlow.cs:84:126:84:126 | x : String | GlobalDataFlow.cs:84:135:84:135 | access to parameter x | -| GlobalDataFlow.cs:84:126:84:126 | x : String | GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | -| GlobalDataFlow.cs:84:126:84:126 | x : String | GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | -| GlobalDataFlow.cs:84:126:84:126 | x : String | GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | -| GlobalDataFlow.cs:84:126:84:126 | x : String[] | GlobalDataFlow.cs:84:126:84:126 | x | -| GlobalDataFlow.cs:84:126:84:126 | x : String[] | GlobalDataFlow.cs:84:126:84:126 | x : String | -| GlobalDataFlow.cs:84:126:84:126 | x : String[] | GlobalDataFlow.cs:84:135:84:135 | access to parameter x | -| GlobalDataFlow.cs:84:126:84:126 | x : String[] | GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | -| GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... | -| GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:70:86:121 | (...) ... | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:106:86:119 | call to method First | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:106:86:119 | call to method First : String | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:68:118:119 | (...) ... | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:117 | call to method First | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:117 | call to method First : String | -| GlobalDataFlow.cs:86:13:86:136 | SSA def(sink16) : IEnumerable | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | -| GlobalDataFlow.cs:86:13:86:136 | SSA def(sink16) : IEnumerable | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 : IEnumerable | -| GlobalDataFlow.cs:86:22:86:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:13:86:136 | SSA def(sink16) | -| GlobalDataFlow.cs:86:22:86:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:13:86:136 | SSA def(sink16) : IEnumerable | -| GlobalDataFlow.cs:86:22:86:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | -| GlobalDataFlow.cs:86:22:86:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 : IEnumerable | -| GlobalDataFlow.cs:86:44:86:62 | array creation of type String[] : String[] | GlobalDataFlow.cs:86:23:86:62 | (...) ... | -| GlobalDataFlow.cs:86:44:86:62 | array creation of type String[] : String[] | GlobalDataFlow.cs:86:23:86:62 | (...) ... : String[] | -| GlobalDataFlow.cs:86:59:86:60 | "" : String | GlobalDataFlow.cs:86:23:86:62 | (...) ... | -| GlobalDataFlow.cs:86:59:86:60 | "" : String | GlobalDataFlow.cs:86:23:86:62 | (...) ... : String[] | -| GlobalDataFlow.cs:86:59:86:60 | "" : String | GlobalDataFlow.cs:86:44:86:62 | array creation of type String[] | -| GlobalDataFlow.cs:86:59:86:60 | "" : String | GlobalDataFlow.cs:86:44:86:62 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable | GlobalDataFlow.cs:86:129:86:129 | y | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable | GlobalDataFlow.cs:86:129:86:129 | y : IEnumerable | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | GlobalDataFlow.cs:86:129:86:129 | y | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | GlobalDataFlow.cs:86:129:86:129 | y : String[] | -| GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] | GlobalDataFlow.cs:86:70:86:121 | (...) ... | -| GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:70:86:121 | (...) ... | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:106:86:119 | call to method First | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:106:86:119 | call to method First : String | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:68:118:119 | (...) ... | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:117 | call to method First | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:117 | call to method First : String | -| GlobalDataFlow.cs:86:106:86:119 | call to method First : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... | -| GlobalDataFlow.cs:86:106:86:119 | call to method First : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | -| GlobalDataFlow.cs:86:106:86:119 | call to method First : String | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] | -| GlobalDataFlow.cs:86:106:86:119 | call to method First : String | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:13:86:136 | SSA def(sink16) | -| GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:13:86:136 | SSA def(sink16) : IEnumerable | -| GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:22:86:136 | call to method Zip | -| GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:22:86:136 | call to method Zip : IEnumerable | -| GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | -| GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 : IEnumerable | -| GlobalDataFlow.cs:86:129:86:129 | y : IEnumerable | GlobalDataFlow.cs:86:129:86:129 | y | -| GlobalDataFlow.cs:86:129:86:129 | y : IEnumerable | GlobalDataFlow.cs:86:129:86:129 | y : String | -| GlobalDataFlow.cs:86:129:86:129 | y : IEnumerable | GlobalDataFlow.cs:86:135:86:135 | access to parameter y | -| GlobalDataFlow.cs:86:129:86:129 | y : IEnumerable | GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String | -| GlobalDataFlow.cs:86:129:86:129 | y : Object | GlobalDataFlow.cs:86:129:86:129 | y | -| GlobalDataFlow.cs:86:129:86:129 | y : Object | GlobalDataFlow.cs:86:129:86:129 | y : String | -| GlobalDataFlow.cs:86:129:86:129 | y : Object | GlobalDataFlow.cs:86:135:86:135 | access to parameter y | -| GlobalDataFlow.cs:86:129:86:129 | y : Object | GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String | -| GlobalDataFlow.cs:86:129:86:129 | y : String | GlobalDataFlow.cs:86:135:86:135 | access to parameter y | -| GlobalDataFlow.cs:86:129:86:129 | y : String | GlobalDataFlow.cs:86:135:86:135 | access to parameter y | -| GlobalDataFlow.cs:86:129:86:129 | y : String | GlobalDataFlow.cs:86:135:86:135 | access to parameter y | -| GlobalDataFlow.cs:86:129:86:129 | y : String | GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String | -| GlobalDataFlow.cs:86:129:86:129 | y : String | GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String | -| GlobalDataFlow.cs:86:129:86:129 | y : String | GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String | -| GlobalDataFlow.cs:86:129:86:129 | y : String[] | GlobalDataFlow.cs:86:129:86:129 | y | -| GlobalDataFlow.cs:86:129:86:129 | y : String[] | GlobalDataFlow.cs:86:129:86:129 | y : String | -| GlobalDataFlow.cs:86:129:86:129 | y : String[] | GlobalDataFlow.cs:86:135:86:135 | access to parameter y | -| GlobalDataFlow.cs:86:129:86:129 | y : String[] | GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String | -| GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... | -| GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:13:88:70 | SSA def(sink17) : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | -| GlobalDataFlow.cs:88:13:88:70 | SSA def(sink17) : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 : String | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:49:88:49 | s | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:49:88:49 | s : IEnumerable | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:88 | call to method First | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:88 | call to method First : String | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First : String | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:88:22:88:70 | call to method Aggregate : String | GlobalDataFlow.cs:88:13:88:70 | SSA def(sink17) | -| GlobalDataFlow.cs:88:22:88:70 | call to method Aggregate : String | GlobalDataFlow.cs:88:13:88:70 | SSA def(sink17) : String | -| GlobalDataFlow.cs:88:22:88:70 | call to method Aggregate : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | -| GlobalDataFlow.cs:88:22:88:70 | call to method Aggregate : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 : String | -| GlobalDataFlow.cs:88:39:88:40 | "" : String | GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... | -| GlobalDataFlow.cs:88:39:88:40 | "" : String | GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:39:88:40 | "" : String | GlobalDataFlow.cs:88:44:88:46 | acc | -| GlobalDataFlow.cs:88:39:88:40 | "" : String | GlobalDataFlow.cs:88:44:88:46 | acc : String | -| GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | GlobalDataFlow.cs:88:64:88:64 | x | -| GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | GlobalDataFlow.cs:88:64:88:64 | x : String | -| GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... | -| GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:44:88:46 | acc : Object | GlobalDataFlow.cs:88:44:88:46 | acc | -| GlobalDataFlow.cs:88:44:88:46 | acc : Object | GlobalDataFlow.cs:88:44:88:46 | acc : String | -| GlobalDataFlow.cs:88:44:88:46 | acc : Object | GlobalDataFlow.cs:88:55:88:57 | access to parameter acc | -| GlobalDataFlow.cs:88:44:88:46 | acc : Object | GlobalDataFlow.cs:88:55:88:57 | access to parameter acc : String | -| GlobalDataFlow.cs:88:44:88:46 | acc : Object | GlobalDataFlow.cs:88:55:88:61 | ... + ... | -| GlobalDataFlow.cs:88:44:88:46 | acc : Object | GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:44:88:46 | acc | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:44:88:46 | acc : String | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:57 | access to parameter acc | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:57 | access to parameter acc | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:57 | access to parameter acc | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:57 | access to parameter acc : String | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:57 | access to parameter acc : String | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:57 | access to parameter acc : String | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | -| GlobalDataFlow.cs:88:49:88:49 | s : IEnumerable | GlobalDataFlow.cs:88:49:88:49 | s | -| GlobalDataFlow.cs:88:49:88:49 | s : IEnumerable | GlobalDataFlow.cs:88:49:88:49 | s : String | -| GlobalDataFlow.cs:88:49:88:49 | s : IEnumerable | GlobalDataFlow.cs:88:55:88:61 | ... + ... | -| GlobalDataFlow.cs:88:49:88:49 | s : IEnumerable | GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | -| GlobalDataFlow.cs:88:49:88:49 | s : IEnumerable | GlobalDataFlow.cs:88:61:88:61 | access to parameter s | -| GlobalDataFlow.cs:88:49:88:49 | s : IEnumerable | GlobalDataFlow.cs:88:61:88:61 | access to parameter s : String | -| GlobalDataFlow.cs:88:49:88:49 | s : Object | GlobalDataFlow.cs:88:49:88:49 | s | -| GlobalDataFlow.cs:88:49:88:49 | s : Object | GlobalDataFlow.cs:88:49:88:49 | s : String | -| GlobalDataFlow.cs:88:49:88:49 | s : Object | GlobalDataFlow.cs:88:55:88:61 | ... + ... | -| GlobalDataFlow.cs:88:49:88:49 | s : Object | GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | -| GlobalDataFlow.cs:88:49:88:49 | s : Object | GlobalDataFlow.cs:88:61:88:61 | access to parameter s | -| GlobalDataFlow.cs:88:49:88:49 | s : Object | GlobalDataFlow.cs:88:61:88:61 | access to parameter s : String | -| GlobalDataFlow.cs:88:49:88:49 | s : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... | -| GlobalDataFlow.cs:88:49:88:49 | s : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... | -| GlobalDataFlow.cs:88:49:88:49 | s : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | -| GlobalDataFlow.cs:88:49:88:49 | s : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | -| GlobalDataFlow.cs:88:49:88:49 | s : String | GlobalDataFlow.cs:88:61:88:61 | access to parameter s | -| GlobalDataFlow.cs:88:49:88:49 | s : String | GlobalDataFlow.cs:88:61:88:61 | access to parameter s | -| GlobalDataFlow.cs:88:49:88:49 | s : String | GlobalDataFlow.cs:88:61:88:61 | access to parameter s : String | -| GlobalDataFlow.cs:88:49:88:49 | s : String | GlobalDataFlow.cs:88:61:88:61 | access to parameter s : String | -| GlobalDataFlow.cs:88:55:88:57 | access to parameter acc : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... | -| GlobalDataFlow.cs:88:55:88:57 | access to parameter acc : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... | -| GlobalDataFlow.cs:88:55:88:57 | access to parameter acc : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | -| GlobalDataFlow.cs:88:55:88:57 | access to parameter acc : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | -| GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... | -| GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:61:88:61 | access to parameter s : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... | -| GlobalDataFlow.cs:88:61:88:61 | access to parameter s : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... | -| GlobalDataFlow.cs:88:61:88:61 | access to parameter s : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | -| GlobalDataFlow.cs:88:61:88:61 | access to parameter s : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | -| GlobalDataFlow.cs:88:64:88:64 | x : Object | GlobalDataFlow.cs:88:64:88:64 | x | -| GlobalDataFlow.cs:88:64:88:64 | x : Object | GlobalDataFlow.cs:88:64:88:64 | x : String | -| GlobalDataFlow.cs:88:64:88:64 | x : Object | GlobalDataFlow.cs:88:69:88:69 | access to parameter x | -| GlobalDataFlow.cs:88:64:88:64 | x : Object | GlobalDataFlow.cs:88:69:88:69 | access to parameter x : String | -| GlobalDataFlow.cs:88:64:88:64 | x : String | GlobalDataFlow.cs:88:64:88:64 | x | -| GlobalDataFlow.cs:88:64:88:64 | x : String | GlobalDataFlow.cs:88:64:88:64 | x : String | -| GlobalDataFlow.cs:88:64:88:64 | x : String | GlobalDataFlow.cs:88:69:88:69 | access to parameter x | -| GlobalDataFlow.cs:88:64:88:64 | x : String | GlobalDataFlow.cs:88:69:88:69 | access to parameter x | -| GlobalDataFlow.cs:88:64:88:64 | x : String | GlobalDataFlow.cs:88:69:88:69 | access to parameter x | -| GlobalDataFlow.cs:88:64:88:64 | x : String | GlobalDataFlow.cs:88:69:88:69 | access to parameter x : String | -| GlobalDataFlow.cs:88:64:88:64 | x : String | GlobalDataFlow.cs:88:69:88:69 | access to parameter x : String | -| GlobalDataFlow.cs:88:64:88:64 | x : String | GlobalDataFlow.cs:88:69:88:69 | access to parameter x : String | -| GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String | GlobalDataFlow.cs:88:13:88:70 | SSA def(sink17) | -| GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String | GlobalDataFlow.cs:88:13:88:70 | SSA def(sink17) : String | -| GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String | GlobalDataFlow.cs:88:22:88:70 | call to method Aggregate | -| GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String | GlobalDataFlow.cs:88:22:88:70 | call to method Aggregate : String | -| GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | -| GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 : String | -| GlobalDataFlow.cs:88:69:88:69 | access to parameter x : String | GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... | -| GlobalDataFlow.cs:88:69:88:69 | access to parameter x : String | GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) : Int32 | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 : Int32 | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) : Boolean | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 : Boolean | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) : Int32 | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 : Int32 | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) : Boolean | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 : Boolean | -| GlobalDataFlow.cs:90:23:90:62 | (...) ... : IEnumerable | GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... | -| GlobalDataFlow.cs:90:23:90:62 | (...) ... : IEnumerable | GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:23:90:62 | (...) ... : IEnumerable | GlobalDataFlow.cs:90:97:90:97 | s | -| GlobalDataFlow.cs:90:23:90:62 | (...) ... : IEnumerable | GlobalDataFlow.cs:90:97:90:97 | s : IEnumerable | -| GlobalDataFlow.cs:90:23:90:62 | (...) ... : String[] | GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... | -| GlobalDataFlow.cs:90:23:90:62 | (...) ... : String[] | GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:23:90:62 | (...) ... : String[] | GlobalDataFlow.cs:90:97:90:97 | s | -| GlobalDataFlow.cs:90:23:90:62 | (...) ... : String[] | GlobalDataFlow.cs:90:97:90:97 | s : String[] | -| GlobalDataFlow.cs:90:44:90:62 | array creation of type String[] : String[] | GlobalDataFlow.cs:90:23:90:62 | (...) ... | -| GlobalDataFlow.cs:90:44:90:62 | array creation of type String[] : String[] | GlobalDataFlow.cs:90:23:90:62 | (...) ... : String[] | -| GlobalDataFlow.cs:90:59:90:60 | "" : String | GlobalDataFlow.cs:90:23:90:62 | (...) ... | -| GlobalDataFlow.cs:90:59:90:60 | "" : String | GlobalDataFlow.cs:90:23:90:62 | (...) ... : String[] | -| GlobalDataFlow.cs:90:59:90:60 | "" : String | GlobalDataFlow.cs:90:44:90:62 | array creation of type String[] | -| GlobalDataFlow.cs:90:59:90:60 | "" : String | GlobalDataFlow.cs:90:44:90:62 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:88 | call to method First | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:88 | call to method First : String | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First : String | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:90:75:90:88 | call to method First : String | GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... | -| GlobalDataFlow.cs:90:75:90:88 | call to method First : String | GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:75:90:88 | call to method First : String | GlobalDataFlow.cs:90:92:90:94 | acc | -| GlobalDataFlow.cs:90:75:90:88 | call to method First : String | GlobalDataFlow.cs:90:92:90:94 | acc : String | -| GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:90:112:90:112 | x | -| GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:90:112:90:112 | x : String | -| GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... | -| GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:92:90:94 | acc : Object | GlobalDataFlow.cs:90:92:90:94 | acc | -| GlobalDataFlow.cs:90:92:90:94 | acc : Object | GlobalDataFlow.cs:90:92:90:94 | acc : String | -| GlobalDataFlow.cs:90:92:90:94 | acc : Object | GlobalDataFlow.cs:90:103:90:105 | access to parameter acc | -| GlobalDataFlow.cs:90:92:90:94 | acc : Object | GlobalDataFlow.cs:90:103:90:105 | access to parameter acc : String | -| GlobalDataFlow.cs:90:92:90:94 | acc : Object | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:92:90:94 | acc : Object | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:92:90:94 | acc | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:92:90:94 | acc : String | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:105 | access to parameter acc | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:105 | access to parameter acc | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:105 | access to parameter acc | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:105 | access to parameter acc : String | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:105 | access to parameter acc : String | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:105 | access to parameter acc : String | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:97:90:97 | s : IEnumerable | GlobalDataFlow.cs:90:97:90:97 | s | -| GlobalDataFlow.cs:90:97:90:97 | s : IEnumerable | GlobalDataFlow.cs:90:97:90:97 | s : String | -| GlobalDataFlow.cs:90:97:90:97 | s : IEnumerable | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:97:90:97 | s : IEnumerable | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:97:90:97 | s : IEnumerable | GlobalDataFlow.cs:90:109:90:109 | access to parameter s | -| GlobalDataFlow.cs:90:97:90:97 | s : IEnumerable | GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | -| GlobalDataFlow.cs:90:97:90:97 | s : Object | GlobalDataFlow.cs:90:97:90:97 | s | -| GlobalDataFlow.cs:90:97:90:97 | s : Object | GlobalDataFlow.cs:90:97:90:97 | s : String | -| GlobalDataFlow.cs:90:97:90:97 | s : Object | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:97:90:97 | s : Object | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:97:90:97 | s : Object | GlobalDataFlow.cs:90:109:90:109 | access to parameter s | -| GlobalDataFlow.cs:90:97:90:97 | s : Object | GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:109:90:109 | access to parameter s | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:109:90:109 | access to parameter s | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:109:90:109 | access to parameter s | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | -| GlobalDataFlow.cs:90:97:90:97 | s : String[] | GlobalDataFlow.cs:90:97:90:97 | s | -| GlobalDataFlow.cs:90:97:90:97 | s : String[] | GlobalDataFlow.cs:90:97:90:97 | s : String | -| GlobalDataFlow.cs:90:97:90:97 | s : String[] | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:97:90:97 | s : String[] | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:97:90:97 | s : String[] | GlobalDataFlow.cs:90:109:90:109 | access to parameter s | -| GlobalDataFlow.cs:90:97:90:97 | s : String[] | GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | -| GlobalDataFlow.cs:90:103:90:105 | access to parameter acc : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:103:90:105 | access to parameter acc : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:103:90:105 | access to parameter acc : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:103:90:105 | access to parameter acc : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... | -| GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:112:90:112 | x : Object | GlobalDataFlow.cs:90:112:90:112 | x | -| GlobalDataFlow.cs:90:112:90:112 | x : Object | GlobalDataFlow.cs:90:112:90:112 | x : String | -| GlobalDataFlow.cs:90:112:90:112 | x : Object | GlobalDataFlow.cs:90:117:90:117 | access to parameter x | -| GlobalDataFlow.cs:90:112:90:112 | x : Object | GlobalDataFlow.cs:90:117:90:117 | access to parameter x : String | -| GlobalDataFlow.cs:90:112:90:112 | x : String | GlobalDataFlow.cs:90:112:90:112 | x | -| GlobalDataFlow.cs:90:112:90:112 | x : String | GlobalDataFlow.cs:90:112:90:112 | x : String | -| GlobalDataFlow.cs:90:112:90:112 | x : String | GlobalDataFlow.cs:90:117:90:117 | access to parameter x | -| GlobalDataFlow.cs:90:112:90:112 | x : String | GlobalDataFlow.cs:90:117:90:117 | access to parameter x | -| GlobalDataFlow.cs:90:112:90:112 | x : String | GlobalDataFlow.cs:90:117:90:117 | access to parameter x | -| GlobalDataFlow.cs:90:112:90:112 | x : String | GlobalDataFlow.cs:90:117:90:117 | access to parameter x : String | -| GlobalDataFlow.cs:90:112:90:112 | x : String | GlobalDataFlow.cs:90:117:90:117 | access to parameter x : String | -| GlobalDataFlow.cs:90:112:90:112 | x : String | GlobalDataFlow.cs:90:117:90:117 | access to parameter x : String | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) : Int32 | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 : Int32 | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) : Boolean | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 : Boolean | -| GlobalDataFlow.cs:90:117:90:117 | access to parameter x : String | GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... | -| GlobalDataFlow.cs:90:117:90:117 | access to parameter x : String | GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) : Int32 | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 : Int32 | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) : Boolean | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 : Boolean | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) : Int32 | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 : Int32 | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) : Boolean | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 : Boolean | -| GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) : Int32 | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | -| GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) : Int32 | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 : Int32 | -| GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse | -| GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) | -| GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) : Boolean | -| GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | -| GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 : Boolean | -| GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) : Boolean | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | -| GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) : Boolean | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 : Boolean | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : T | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : T | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : T | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : T | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : T | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : T | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:100:31:100:32 | "" : String | GlobalDataFlow.cs:100:24:100:33 | call to method Return | -| GlobalDataFlow.cs:100:31:100:32 | "" : String | GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | -| GlobalDataFlow.cs:100:31:100:32 | "" : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:100:31:100:32 | "" : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] | -| GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 | -| GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] | -| GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 | -| GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : Object | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : Object | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 : Object | -| GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : String | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : String | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : T | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : T | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : Object | GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : Object | GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : Object | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : Object | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : Object | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 : Object | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : String | GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : String | GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : String | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : String | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : T | GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : T | GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : T | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : T | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : Object | GlobalDataFlow.cs:102:20:102:103 | (...) ... | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : Object | GlobalDataFlow.cs:102:20:102:103 | (...) ... : Object | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : String | GlobalDataFlow.cs:102:20:102:103 | (...) ... | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : String | GlobalDataFlow.cs:102:20:102:103 | (...) ... : String | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : T | GlobalDataFlow.cs:102:20:102:103 | (...) ... | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : T | GlobalDataFlow.cs:102:20:102:103 | (...) ... : T | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : String | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : T | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | GlobalDataFlow.cs:275:26:275:26 | x : T | -| GlobalDataFlow.cs:104:19:104:20 | "" : String | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:104:19:104:20 | "" : String | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:104:19:104:20 | "" : String | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:104:19:104:20 | "" : String | GlobalDataFlow.cs:281:32:281:32 | x : String | -| GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:105:15:105:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:105:15:105:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:105:15:105:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:105:15:105:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:281:32:281:32 | x : Object | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : String | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | GlobalDataFlow.cs:281:32:281:32 | x : String | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : T | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | GlobalDataFlow.cs:281:32:281:32 | x : T | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : String | GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : String | GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : String | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : String | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : String | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : String | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:19:108:20 | "" : String | GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:108:19:108:20 | "" : String | GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:108:19:108:20 | "" : String | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:108:19:108:20 | "" : String | GlobalDataFlow.cs:287:32:287:32 | x : String | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : String | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : String | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : T | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : T | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:287:50:287:50 | z | -| GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:287:50:287:50 | z : String | -| GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:287:50:287:50 | z | -| GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:287:50:287:50 | z : T | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : Object | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:287:32:287:32 | x : Object | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : String | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : String | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | GlobalDataFlow.cs:287:32:287:32 | x : String | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : T | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : T | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | GlobalDataFlow.cs:287:32:287:32 | x : T | -| GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : Object | GlobalDataFlow.cs:124:39:124:43 | access to local variable sink1 | -| GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : Object | GlobalDataFlow.cs:124:39:124:43 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : String | GlobalDataFlow.cs:124:39:124:43 | access to local variable sink1 | -| GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : String | GlobalDataFlow.cs:124:39:124:43 | access to local variable sink1 : String | -| GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : T | GlobalDataFlow.cs:124:39:124:43 | access to local variable sink1 | -| GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : T | GlobalDataFlow.cs:124:39:124:43 | access to local variable sink1 : T | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:287:50:287:50 | z | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:287:50:287:50 | z : String | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:287:50:287:50 | z | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:287:50:287:50 | z : T | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable | GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven | -| GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable | GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | -| GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable | GlobalDataFlow.cs:426:71:426:71 | e | -| GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable | GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | -| GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven | -| GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | -| GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | GlobalDataFlow.cs:426:71:426:71 | e | -| GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | GlobalDataFlow.cs:426:71:426:71 | e : String[] | -| GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | GlobalDataFlow.cs:112:25:112:70 | (...) ... | -| GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:112:84:112:84 | x : Object | GlobalDataFlow.cs:112:84:112:84 | x | -| GlobalDataFlow.cs:112:84:112:84 | x : Object | GlobalDataFlow.cs:112:84:112:84 | x : String | -| GlobalDataFlow.cs:112:84:112:84 | x : Object | GlobalDataFlow.cs:112:89:112:89 | access to parameter x | -| GlobalDataFlow.cs:112:84:112:84 | x : Object | GlobalDataFlow.cs:112:89:112:89 | access to parameter x : String | -| GlobalDataFlow.cs:112:84:112:84 | x : String | GlobalDataFlow.cs:112:89:112:89 | access to parameter x | -| GlobalDataFlow.cs:112:84:112:84 | x : String | GlobalDataFlow.cs:112:89:112:89 | access to parameter x : String | -| GlobalDataFlow.cs:112:84:112:84 | x : T | GlobalDataFlow.cs:112:89:112:89 | access to parameter x | -| GlobalDataFlow.cs:112:84:112:84 | x : T | GlobalDataFlow.cs:112:89:112:89 | access to parameter x : T | -| GlobalDataFlow.cs:112:84:112:89 | (...) => ... : Func | GlobalDataFlow.cs:426:85:426:85 | f | -| GlobalDataFlow.cs:112:84:112:89 | (...) => ... : Func | GlobalDataFlow.cs:426:85:426:85 | f : Func | -| GlobalDataFlow.cs:112:89:112:89 | access to parameter x : String | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:112:89:112:89 | access to parameter x : String | GlobalDataFlow.cs:431:44:431:47 | delegate call : String | -| GlobalDataFlow.cs:114:9:114:82 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:115:15:115:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:114:9:114:82 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:115:15:115:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:114:20:114:82 | call to method Select : IEnumerable | GlobalDataFlow.cs:114:9:114:82 | SSA def(nonSink1) | -| GlobalDataFlow.cs:114:20:114:82 | call to method Select : IEnumerable | GlobalDataFlow.cs:114:9:114:82 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:114:20:114:82 | call to method Select : IEnumerable | GlobalDataFlow.cs:115:15:115:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:114:20:114:82 | call to method Select : IEnumerable | GlobalDataFlow.cs:115:15:115:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable | GlobalDataFlow.cs:114:76:114:76 | x | -| GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable | GlobalDataFlow.cs:114:76:114:76 | x : IEnumerable | -| GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable | GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... | -| GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable | GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... : String | -| GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | GlobalDataFlow.cs:114:76:114:76 | x | -| GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | GlobalDataFlow.cs:114:76:114:76 | x : String[] | -| GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... | -| GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... : String | -| GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] | -| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] | -| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:114:76:114:76 | x : IEnumerable | GlobalDataFlow.cs:114:76:114:76 | x | -| GlobalDataFlow.cs:114:76:114:76 | x : IEnumerable | GlobalDataFlow.cs:114:76:114:76 | x : String | -| GlobalDataFlow.cs:114:76:114:76 | x : IEnumerable | GlobalDataFlow.cs:114:81:114:81 | access to parameter x | -| GlobalDataFlow.cs:114:76:114:76 | x : IEnumerable | GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String | -| GlobalDataFlow.cs:114:76:114:76 | x : Object | GlobalDataFlow.cs:114:76:114:76 | x | -| GlobalDataFlow.cs:114:76:114:76 | x : Object | GlobalDataFlow.cs:114:76:114:76 | x : String | -| GlobalDataFlow.cs:114:76:114:76 | x : Object | GlobalDataFlow.cs:114:81:114:81 | access to parameter x | -| GlobalDataFlow.cs:114:76:114:76 | x : Object | GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String | -| GlobalDataFlow.cs:114:76:114:76 | x : String | GlobalDataFlow.cs:114:81:114:81 | access to parameter x | -| GlobalDataFlow.cs:114:76:114:76 | x : String | GlobalDataFlow.cs:114:81:114:81 | access to parameter x | -| GlobalDataFlow.cs:114:76:114:76 | x : String | GlobalDataFlow.cs:114:81:114:81 | access to parameter x | -| GlobalDataFlow.cs:114:76:114:76 | x : String | GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String | -| GlobalDataFlow.cs:114:76:114:76 | x : String | GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String | -| GlobalDataFlow.cs:114:76:114:76 | x : String | GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String | -| GlobalDataFlow.cs:114:76:114:76 | x : String[] | GlobalDataFlow.cs:114:76:114:76 | x | -| GlobalDataFlow.cs:114:76:114:76 | x : String[] | GlobalDataFlow.cs:114:76:114:76 | x : String | -| GlobalDataFlow.cs:114:76:114:76 | x : String[] | GlobalDataFlow.cs:114:81:114:81 | access to parameter x | -| GlobalDataFlow.cs:114:76:114:76 | x : String[] | GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String | -| GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... : String | GlobalDataFlow.cs:114:9:114:82 | SSA def(nonSink1) | -| GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... : String | GlobalDataFlow.cs:114:9:114:82 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... : String | GlobalDataFlow.cs:114:20:114:82 | call to method Select | -| GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... : String | GlobalDataFlow.cs:114:20:114:82 | call to method Select : IEnumerable | -| GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... : String | GlobalDataFlow.cs:115:15:115:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... : String | GlobalDataFlow.cs:115:15:115:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String | GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... | -| GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String | GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... : String | -| GlobalDataFlow.cs:116:9:116:134 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:117:15:117:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:116:9:116:134 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:117:15:117:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:116:20:116:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:116:9:116:134 | SSA def(nonSink1) | -| GlobalDataFlow.cs:116:20:116:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:116:9:116:134 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:116:20:116:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:117:15:117:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:116:20:116:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:117:15:117:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | GlobalDataFlow.cs:116:21:116:72 | (...) ... | -| GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First : String | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:116:57:116:70 | call to method First : String | GlobalDataFlow.cs:116:21:116:72 | (...) ... | -| GlobalDataFlow.cs:116:57:116:70 | call to method First : String | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] | -| GlobalDataFlow.cs:116:57:116:70 | call to method First : String | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] | -| GlobalDataFlow.cs:116:57:116:70 | call to method First : String | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:116:80:116:119 | (...) ... : IEnumerable | GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... | -| GlobalDataFlow.cs:116:80:116:119 | (...) ... : IEnumerable | GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... : String | -| GlobalDataFlow.cs:116:80:116:119 | (...) ... : IEnumerable | GlobalDataFlow.cs:116:127:116:127 | y | -| GlobalDataFlow.cs:116:80:116:119 | (...) ... : IEnumerable | GlobalDataFlow.cs:116:127:116:127 | y : IEnumerable | -| GlobalDataFlow.cs:116:80:116:119 | (...) ... : String[] | GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... | -| GlobalDataFlow.cs:116:80:116:119 | (...) ... : String[] | GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... : String | -| GlobalDataFlow.cs:116:80:116:119 | (...) ... : String[] | GlobalDataFlow.cs:116:127:116:127 | y | -| GlobalDataFlow.cs:116:80:116:119 | (...) ... : String[] | GlobalDataFlow.cs:116:127:116:127 | y : String[] | -| GlobalDataFlow.cs:116:101:116:119 | array creation of type String[] : String[] | GlobalDataFlow.cs:116:80:116:119 | (...) ... | -| GlobalDataFlow.cs:116:101:116:119 | array creation of type String[] : String[] | GlobalDataFlow.cs:116:80:116:119 | (...) ... : String[] | -| GlobalDataFlow.cs:116:116:116:117 | "" : String | GlobalDataFlow.cs:116:80:116:119 | (...) ... | -| GlobalDataFlow.cs:116:116:116:117 | "" : String | GlobalDataFlow.cs:116:80:116:119 | (...) ... : String[] | -| GlobalDataFlow.cs:116:116:116:117 | "" : String | GlobalDataFlow.cs:116:101:116:119 | array creation of type String[] | -| GlobalDataFlow.cs:116:116:116:117 | "" : String | GlobalDataFlow.cs:116:101:116:119 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... : String | GlobalDataFlow.cs:116:9:116:134 | SSA def(nonSink1) | -| GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... : String | GlobalDataFlow.cs:116:9:116:134 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... : String | GlobalDataFlow.cs:116:20:116:134 | call to method Zip | -| GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... : String | GlobalDataFlow.cs:116:20:116:134 | call to method Zip : IEnumerable | -| GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... : String | GlobalDataFlow.cs:117:15:117:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... : String | GlobalDataFlow.cs:117:15:117:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:116:127:116:127 | y : IEnumerable | GlobalDataFlow.cs:116:127:116:127 | y | -| GlobalDataFlow.cs:116:127:116:127 | y : IEnumerable | GlobalDataFlow.cs:116:127:116:127 | y : String | -| GlobalDataFlow.cs:116:127:116:127 | y : IEnumerable | GlobalDataFlow.cs:116:133:116:133 | access to parameter y | -| GlobalDataFlow.cs:116:127:116:127 | y : IEnumerable | GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String | -| GlobalDataFlow.cs:116:127:116:127 | y : Object | GlobalDataFlow.cs:116:127:116:127 | y | -| GlobalDataFlow.cs:116:127:116:127 | y : Object | GlobalDataFlow.cs:116:127:116:127 | y : String | -| GlobalDataFlow.cs:116:127:116:127 | y : Object | GlobalDataFlow.cs:116:133:116:133 | access to parameter y | -| GlobalDataFlow.cs:116:127:116:127 | y : Object | GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String | -| GlobalDataFlow.cs:116:127:116:127 | y : String | GlobalDataFlow.cs:116:133:116:133 | access to parameter y | -| GlobalDataFlow.cs:116:127:116:127 | y : String | GlobalDataFlow.cs:116:133:116:133 | access to parameter y | -| GlobalDataFlow.cs:116:127:116:127 | y : String | GlobalDataFlow.cs:116:133:116:133 | access to parameter y | -| GlobalDataFlow.cs:116:127:116:127 | y : String | GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String | -| GlobalDataFlow.cs:116:127:116:127 | y : String | GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String | -| GlobalDataFlow.cs:116:127:116:127 | y : String | GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String | -| GlobalDataFlow.cs:116:127:116:127 | y : String[] | GlobalDataFlow.cs:116:127:116:127 | y | -| GlobalDataFlow.cs:116:127:116:127 | y : String[] | GlobalDataFlow.cs:116:127:116:127 | y : String | -| GlobalDataFlow.cs:116:127:116:127 | y : String[] | GlobalDataFlow.cs:116:133:116:133 | access to parameter y | -| GlobalDataFlow.cs:116:127:116:127 | y : String[] | GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String | -| GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String | GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... | -| GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String | GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... : String | -| GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 | -| GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:118:21:118:60 | (...) ... : IEnumerable | GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... | -| GlobalDataFlow.cs:118:21:118:60 | (...) ... : IEnumerable | GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | -| GlobalDataFlow.cs:118:21:118:60 | (...) ... : IEnumerable | GlobalDataFlow.cs:118:124:118:124 | x | -| GlobalDataFlow.cs:118:21:118:60 | (...) ... : IEnumerable | GlobalDataFlow.cs:118:124:118:124 | x : IEnumerable | -| GlobalDataFlow.cs:118:21:118:60 | (...) ... : String[] | GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... | -| GlobalDataFlow.cs:118:21:118:60 | (...) ... : String[] | GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | -| GlobalDataFlow.cs:118:21:118:60 | (...) ... : String[] | GlobalDataFlow.cs:118:124:118:124 | x | -| GlobalDataFlow.cs:118:21:118:60 | (...) ... : String[] | GlobalDataFlow.cs:118:124:118:124 | x : String[] | -| GlobalDataFlow.cs:118:42:118:60 | array creation of type String[] : String[] | GlobalDataFlow.cs:118:21:118:60 | (...) ... | -| GlobalDataFlow.cs:118:42:118:60 | array creation of type String[] : String[] | GlobalDataFlow.cs:118:21:118:60 | (...) ... : String[] | -| GlobalDataFlow.cs:118:57:118:58 | "" : String | GlobalDataFlow.cs:118:21:118:60 | (...) ... | -| GlobalDataFlow.cs:118:57:118:58 | "" : String | GlobalDataFlow.cs:118:21:118:60 | (...) ... : String[] | -| GlobalDataFlow.cs:118:57:118:58 | "" : String | GlobalDataFlow.cs:118:42:118:60 | array creation of type String[] | -| GlobalDataFlow.cs:118:57:118:58 | "" : String | GlobalDataFlow.cs:118:42:118:60 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | GlobalDataFlow.cs:118:68:118:119 | (...) ... | -| GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] | -| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:68:118:119 | (...) ... | -| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] | -| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] | -| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:117 | call to method First | -| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:117 | call to method First : String | -| GlobalDataFlow.cs:118:104:118:117 | call to method First : String | GlobalDataFlow.cs:118:68:118:119 | (...) ... | -| GlobalDataFlow.cs:118:104:118:117 | call to method First : String | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] | -| GlobalDataFlow.cs:118:104:118:117 | call to method First : String | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] | -| GlobalDataFlow.cs:118:104:118:117 | call to method First : String | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) | -| GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | GlobalDataFlow.cs:118:20:118:134 | call to method Zip | -| GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | -| GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 | -| GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:118:124:118:124 | x : IEnumerable | GlobalDataFlow.cs:118:124:118:124 | x | -| GlobalDataFlow.cs:118:124:118:124 | x : IEnumerable | GlobalDataFlow.cs:118:124:118:124 | x : String | -| GlobalDataFlow.cs:118:124:118:124 | x : IEnumerable | GlobalDataFlow.cs:118:133:118:133 | access to parameter x | -| GlobalDataFlow.cs:118:124:118:124 | x : IEnumerable | GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String | -| GlobalDataFlow.cs:118:124:118:124 | x : Object | GlobalDataFlow.cs:118:124:118:124 | x | -| GlobalDataFlow.cs:118:124:118:124 | x : Object | GlobalDataFlow.cs:118:124:118:124 | x : String | -| GlobalDataFlow.cs:118:124:118:124 | x : Object | GlobalDataFlow.cs:118:133:118:133 | access to parameter x | -| GlobalDataFlow.cs:118:124:118:124 | x : Object | GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String | -| GlobalDataFlow.cs:118:124:118:124 | x : String | GlobalDataFlow.cs:118:133:118:133 | access to parameter x | -| GlobalDataFlow.cs:118:124:118:124 | x : String | GlobalDataFlow.cs:118:133:118:133 | access to parameter x | -| GlobalDataFlow.cs:118:124:118:124 | x : String | GlobalDataFlow.cs:118:133:118:133 | access to parameter x | -| GlobalDataFlow.cs:118:124:118:124 | x : String | GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String | -| GlobalDataFlow.cs:118:124:118:124 | x : String | GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String | -| GlobalDataFlow.cs:118:124:118:124 | x : String | GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String | -| GlobalDataFlow.cs:118:124:118:124 | x : String[] | GlobalDataFlow.cs:118:124:118:124 | x | -| GlobalDataFlow.cs:118:124:118:124 | x : String[] | GlobalDataFlow.cs:118:124:118:124 | x : String | -| GlobalDataFlow.cs:118:124:118:124 | x : String[] | GlobalDataFlow.cs:118:133:118:133 | access to parameter x | -| GlobalDataFlow.cs:118:124:118:124 | x : String[] | GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String | -| GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String | GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... | -| GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String | GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | -| GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 : IEnumerable | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 | -| GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 : IEnumerable | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:120:9:120:64 | SSA def(nonSink0) : String | GlobalDataFlow.cs:121:15:121:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:120:9:120:64 | SSA def(nonSink0) : String | GlobalDataFlow.cs:121:15:121:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:120:20:120:64 | call to method Aggregate : String | GlobalDataFlow.cs:120:9:120:64 | SSA def(nonSink0) | -| GlobalDataFlow.cs:120:20:120:64 | call to method Aggregate : String | GlobalDataFlow.cs:120:9:120:64 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:120:20:120:64 | call to method Aggregate : String | GlobalDataFlow.cs:121:15:121:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:120:20:120:64 | call to method Aggregate : String | GlobalDataFlow.cs:121:15:121:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:120:37:120:38 | "" : String | GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... | -| GlobalDataFlow.cs:120:37:120:38 | "" : String | GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... : String | -| GlobalDataFlow.cs:120:37:120:38 | "" : String | GlobalDataFlow.cs:120:42:120:44 | acc | -| GlobalDataFlow.cs:120:37:120:38 | "" : String | GlobalDataFlow.cs:120:42:120:44 | acc : String | -| GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... : String | GlobalDataFlow.cs:120:58:120:58 | x | -| GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... : String | GlobalDataFlow.cs:120:58:120:58 | x : String | -| GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... : String | GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... | -| GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... : String | GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... : String | -| GlobalDataFlow.cs:120:42:120:44 | acc : Object | GlobalDataFlow.cs:120:42:120:44 | acc | -| GlobalDataFlow.cs:120:42:120:44 | acc : Object | GlobalDataFlow.cs:120:42:120:44 | acc : String | -| GlobalDataFlow.cs:120:42:120:44 | acc : Object | GlobalDataFlow.cs:120:53:120:55 | access to parameter acc | -| GlobalDataFlow.cs:120:42:120:44 | acc : Object | GlobalDataFlow.cs:120:53:120:55 | access to parameter acc : String | -| GlobalDataFlow.cs:120:42:120:44 | acc : String | GlobalDataFlow.cs:120:42:120:44 | acc | -| GlobalDataFlow.cs:120:42:120:44 | acc : String | GlobalDataFlow.cs:120:42:120:44 | acc : String | -| GlobalDataFlow.cs:120:42:120:44 | acc : String | GlobalDataFlow.cs:120:53:120:55 | access to parameter acc | -| GlobalDataFlow.cs:120:42:120:44 | acc : String | GlobalDataFlow.cs:120:53:120:55 | access to parameter acc | -| GlobalDataFlow.cs:120:42:120:44 | acc : String | GlobalDataFlow.cs:120:53:120:55 | access to parameter acc | -| GlobalDataFlow.cs:120:42:120:44 | acc : String | GlobalDataFlow.cs:120:53:120:55 | access to parameter acc : String | -| GlobalDataFlow.cs:120:42:120:44 | acc : String | GlobalDataFlow.cs:120:53:120:55 | access to parameter acc : String | -| GlobalDataFlow.cs:120:42:120:44 | acc : String | GlobalDataFlow.cs:120:53:120:55 | access to parameter acc : String | -| GlobalDataFlow.cs:120:53:120:55 | access to parameter acc : String | GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... | -| GlobalDataFlow.cs:120:53:120:55 | access to parameter acc : String | GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... : String | -| GlobalDataFlow.cs:120:58:120:58 | x : Object | GlobalDataFlow.cs:120:58:120:58 | x | -| GlobalDataFlow.cs:120:58:120:58 | x : Object | GlobalDataFlow.cs:120:58:120:58 | x : String | -| GlobalDataFlow.cs:120:58:120:58 | x : Object | GlobalDataFlow.cs:120:63:120:63 | access to parameter x | -| GlobalDataFlow.cs:120:58:120:58 | x : Object | GlobalDataFlow.cs:120:63:120:63 | access to parameter x : String | -| GlobalDataFlow.cs:120:58:120:58 | x : String | GlobalDataFlow.cs:120:58:120:58 | x | -| GlobalDataFlow.cs:120:58:120:58 | x : String | GlobalDataFlow.cs:120:58:120:58 | x : String | -| GlobalDataFlow.cs:120:58:120:58 | x : String | GlobalDataFlow.cs:120:63:120:63 | access to parameter x | -| GlobalDataFlow.cs:120:58:120:58 | x : String | GlobalDataFlow.cs:120:63:120:63 | access to parameter x | -| GlobalDataFlow.cs:120:58:120:58 | x : String | GlobalDataFlow.cs:120:63:120:63 | access to parameter x | -| GlobalDataFlow.cs:120:58:120:58 | x : String | GlobalDataFlow.cs:120:63:120:63 | access to parameter x : String | -| GlobalDataFlow.cs:120:58:120:58 | x : String | GlobalDataFlow.cs:120:63:120:63 | access to parameter x : String | -| GlobalDataFlow.cs:120:58:120:58 | x : String | GlobalDataFlow.cs:120:63:120:63 | access to parameter x : String | -| GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... : String | GlobalDataFlow.cs:120:9:120:64 | SSA def(nonSink0) | -| GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... : String | GlobalDataFlow.cs:120:9:120:64 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... : String | GlobalDataFlow.cs:120:20:120:64 | call to method Aggregate | -| GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... : String | GlobalDataFlow.cs:120:20:120:64 | call to method Aggregate : String | -| GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... : String | GlobalDataFlow.cs:121:15:121:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... : String | GlobalDataFlow.cs:121:15:121:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:120:63:120:63 | access to parameter x : String | GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... | -| GlobalDataFlow.cs:120:63:120:63 | access to parameter x : String | GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... : String | -| GlobalDataFlow.cs:122:9:122:69 | SSA def(nonSink0) : String | GlobalDataFlow.cs:123:15:123:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:122:9:122:69 | SSA def(nonSink0) : String | GlobalDataFlow.cs:123:15:123:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:41:122:59 | [output] (...) => ... | -| GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:41:122:59 | [output] (...) => ... : String | -| GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:47:122:47 | s | -| GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:47:122:47 | s : IEnumerable | -| GlobalDataFlow.cs:122:20:122:69 | call to method Aggregate : String | GlobalDataFlow.cs:122:9:122:69 | SSA def(nonSink0) | -| GlobalDataFlow.cs:122:20:122:69 | call to method Aggregate : String | GlobalDataFlow.cs:122:9:122:69 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:122:20:122:69 | call to method Aggregate : String | GlobalDataFlow.cs:123:15:123:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:122:20:122:69 | call to method Aggregate : String | GlobalDataFlow.cs:123:15:123:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:122:37:122:38 | "" : String | GlobalDataFlow.cs:122:41:122:59 | [output] (...) => ... | -| GlobalDataFlow.cs:122:37:122:38 | "" : String | GlobalDataFlow.cs:122:41:122:59 | [output] (...) => ... : String | -| GlobalDataFlow.cs:122:37:122:38 | "" : String | GlobalDataFlow.cs:122:42:122:44 | acc | -| GlobalDataFlow.cs:122:37:122:38 | "" : String | GlobalDataFlow.cs:122:42:122:44 | acc : String | -| GlobalDataFlow.cs:122:42:122:44 | acc : Object | GlobalDataFlow.cs:122:42:122:44 | acc | -| GlobalDataFlow.cs:122:42:122:44 | acc : Object | GlobalDataFlow.cs:122:42:122:44 | acc : String | -| GlobalDataFlow.cs:122:42:122:44 | acc : Object | GlobalDataFlow.cs:122:53:122:55 | access to parameter acc | -| GlobalDataFlow.cs:122:42:122:44 | acc : Object | GlobalDataFlow.cs:122:53:122:55 | access to parameter acc : String | -| GlobalDataFlow.cs:122:42:122:44 | acc : Object | GlobalDataFlow.cs:122:53:122:59 | ... + ... | -| GlobalDataFlow.cs:122:42:122:44 | acc : Object | GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:42:122:44 | acc | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:42:122:44 | acc : String | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:55 | access to parameter acc | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:55 | access to parameter acc | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:55 | access to parameter acc | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:55 | access to parameter acc : String | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:55 | access to parameter acc : String | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:55 | access to parameter acc : String | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | -| GlobalDataFlow.cs:122:47:122:47 | s : IEnumerable | GlobalDataFlow.cs:122:47:122:47 | s | -| GlobalDataFlow.cs:122:47:122:47 | s : IEnumerable | GlobalDataFlow.cs:122:47:122:47 | s : String | -| GlobalDataFlow.cs:122:47:122:47 | s : IEnumerable | GlobalDataFlow.cs:122:53:122:59 | ... + ... | -| GlobalDataFlow.cs:122:47:122:47 | s : IEnumerable | GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | -| GlobalDataFlow.cs:122:47:122:47 | s : IEnumerable | GlobalDataFlow.cs:122:59:122:59 | access to parameter s | -| GlobalDataFlow.cs:122:47:122:47 | s : IEnumerable | GlobalDataFlow.cs:122:59:122:59 | access to parameter s : String | -| GlobalDataFlow.cs:122:47:122:47 | s : Object | GlobalDataFlow.cs:122:47:122:47 | s | -| GlobalDataFlow.cs:122:47:122:47 | s : Object | GlobalDataFlow.cs:122:47:122:47 | s : String | -| GlobalDataFlow.cs:122:47:122:47 | s : Object | GlobalDataFlow.cs:122:53:122:59 | ... + ... | -| GlobalDataFlow.cs:122:47:122:47 | s : Object | GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | -| GlobalDataFlow.cs:122:47:122:47 | s : Object | GlobalDataFlow.cs:122:59:122:59 | access to parameter s | -| GlobalDataFlow.cs:122:47:122:47 | s : Object | GlobalDataFlow.cs:122:59:122:59 | access to parameter s : String | -| GlobalDataFlow.cs:122:47:122:47 | s : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... | -| GlobalDataFlow.cs:122:47:122:47 | s : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... | -| GlobalDataFlow.cs:122:47:122:47 | s : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | -| GlobalDataFlow.cs:122:47:122:47 | s : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | -| GlobalDataFlow.cs:122:47:122:47 | s : String | GlobalDataFlow.cs:122:59:122:59 | access to parameter s | -| GlobalDataFlow.cs:122:47:122:47 | s : String | GlobalDataFlow.cs:122:59:122:59 | access to parameter s | -| GlobalDataFlow.cs:122:47:122:47 | s : String | GlobalDataFlow.cs:122:59:122:59 | access to parameter s : String | -| GlobalDataFlow.cs:122:47:122:47 | s : String | GlobalDataFlow.cs:122:59:122:59 | access to parameter s : String | -| GlobalDataFlow.cs:122:53:122:55 | access to parameter acc : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... | -| GlobalDataFlow.cs:122:53:122:55 | access to parameter acc : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... | -| GlobalDataFlow.cs:122:53:122:55 | access to parameter acc : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | -| GlobalDataFlow.cs:122:53:122:55 | access to parameter acc : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | -| GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | GlobalDataFlow.cs:122:41:122:59 | [output] (...) => ... | -| GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | GlobalDataFlow.cs:122:41:122:59 | [output] (...) => ... : String | -| GlobalDataFlow.cs:122:59:122:59 | access to parameter s : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... | -| GlobalDataFlow.cs:122:59:122:59 | access to parameter s : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... | -| GlobalDataFlow.cs:122:59:122:59 | access to parameter s : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | -| GlobalDataFlow.cs:122:59:122:59 | access to parameter s : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | -| GlobalDataFlow.cs:122:62:122:68 | [output] (...) => ... : String | GlobalDataFlow.cs:122:9:122:69 | SSA def(nonSink0) | -| GlobalDataFlow.cs:122:62:122:68 | [output] (...) => ... : String | GlobalDataFlow.cs:122:9:122:69 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:122:62:122:68 | [output] (...) => ... : String | GlobalDataFlow.cs:122:20:122:69 | call to method Aggregate | -| GlobalDataFlow.cs:122:62:122:68 | [output] (...) => ... : String | GlobalDataFlow.cs:122:20:122:69 | call to method Aggregate : String | -| GlobalDataFlow.cs:122:62:122:68 | [output] (...) => ... : String | GlobalDataFlow.cs:123:15:123:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:122:62:122:68 | [output] (...) => ... : String | GlobalDataFlow.cs:123:15:123:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:122:67:122:68 | "" : String | GlobalDataFlow.cs:122:62:122:68 | [output] (...) => ... | -| GlobalDataFlow.cs:122:67:122:68 | "" : String | GlobalDataFlow.cs:122:62:122:68 | [output] (...) => ... : String | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) : Int32 | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 : Int32 | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) : Boolean | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 : Boolean | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... | -| GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... : String | -| GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | GlobalDataFlow.cs:124:52:124:52 | s | -| GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | GlobalDataFlow.cs:124:52:124:52 | s : IEnumerable | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) : Int32 | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 : Int32 | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) : Boolean | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 : Boolean | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... : String | GlobalDataFlow.cs:124:61:124:61 | x | -| GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... : String | GlobalDataFlow.cs:124:61:124:61 | x : String | -| GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... : String | GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... | -| GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... : String | GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | -| GlobalDataFlow.cs:124:52:124:52 | s : IEnumerable | GlobalDataFlow.cs:124:52:124:52 | s | -| GlobalDataFlow.cs:124:52:124:52 | s : IEnumerable | GlobalDataFlow.cs:124:52:124:52 | s : String | -| GlobalDataFlow.cs:124:52:124:52 | s : IEnumerable | GlobalDataFlow.cs:124:58:124:58 | access to parameter s | -| GlobalDataFlow.cs:124:52:124:52 | s : IEnumerable | GlobalDataFlow.cs:124:58:124:58 | access to parameter s : String | -| GlobalDataFlow.cs:124:52:124:52 | s : Object | GlobalDataFlow.cs:124:52:124:52 | s | -| GlobalDataFlow.cs:124:52:124:52 | s : Object | GlobalDataFlow.cs:124:52:124:52 | s : String | -| GlobalDataFlow.cs:124:52:124:52 | s : Object | GlobalDataFlow.cs:124:58:124:58 | access to parameter s | -| GlobalDataFlow.cs:124:52:124:52 | s : Object | GlobalDataFlow.cs:124:58:124:58 | access to parameter s : String | -| GlobalDataFlow.cs:124:52:124:52 | s : String | GlobalDataFlow.cs:124:58:124:58 | access to parameter s | -| GlobalDataFlow.cs:124:52:124:52 | s : String | GlobalDataFlow.cs:124:58:124:58 | access to parameter s | -| GlobalDataFlow.cs:124:52:124:52 | s : String | GlobalDataFlow.cs:124:58:124:58 | access to parameter s : String | -| GlobalDataFlow.cs:124:52:124:52 | s : String | GlobalDataFlow.cs:124:58:124:58 | access to parameter s : String | -| GlobalDataFlow.cs:124:58:124:58 | access to parameter s : String | GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... | -| GlobalDataFlow.cs:124:58:124:58 | access to parameter s : String | GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... : String | -| GlobalDataFlow.cs:124:61:124:61 | x : Object | GlobalDataFlow.cs:124:61:124:61 | x | -| GlobalDataFlow.cs:124:61:124:61 | x : Object | GlobalDataFlow.cs:124:61:124:61 | x : String | -| GlobalDataFlow.cs:124:61:124:61 | x : Object | GlobalDataFlow.cs:124:66:124:66 | access to parameter x | -| GlobalDataFlow.cs:124:61:124:61 | x : Object | GlobalDataFlow.cs:124:66:124:66 | access to parameter x : String | -| GlobalDataFlow.cs:124:61:124:61 | x : String | GlobalDataFlow.cs:124:61:124:61 | x | -| GlobalDataFlow.cs:124:61:124:61 | x : String | GlobalDataFlow.cs:124:61:124:61 | x : String | -| GlobalDataFlow.cs:124:61:124:61 | x : String | GlobalDataFlow.cs:124:66:124:66 | access to parameter x | -| GlobalDataFlow.cs:124:61:124:61 | x : String | GlobalDataFlow.cs:124:66:124:66 | access to parameter x | -| GlobalDataFlow.cs:124:61:124:61 | x : String | GlobalDataFlow.cs:124:66:124:66 | access to parameter x | -| GlobalDataFlow.cs:124:61:124:61 | x : String | GlobalDataFlow.cs:124:66:124:66 | access to parameter x : String | -| GlobalDataFlow.cs:124:61:124:61 | x : String | GlobalDataFlow.cs:124:66:124:66 | access to parameter x : String | -| GlobalDataFlow.cs:124:61:124:61 | x : String | GlobalDataFlow.cs:124:66:124:66 | access to parameter x : String | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) : Int32 | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 : Int32 | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) : Boolean | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 : Boolean | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:66:124:66 | access to parameter x : String | GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... | -| GlobalDataFlow.cs:124:66:124:66 | access to parameter x : String | GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) : Int32 | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 : Int32 | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) : Boolean | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 : Boolean | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) : Int32 | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 : Int32 | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) : Boolean | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 : Boolean | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) : Int32 | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 | -| GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) : Int32 | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 : Int32 | -| GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse | -| GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) | -| GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) : Boolean | -| GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 | -| GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 : Boolean | -| GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 | -| GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) : Boolean | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 | -| GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) : Boolean | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 : Boolean | -| GlobalDataFlow.cs:134:30:134:64 | SSA def(return) : Func | GlobalDataFlow.cs:135:21:135:27 | access to local variable return | -| GlobalDataFlow.cs:134:30:134:64 | SSA def(return) : Func | GlobalDataFlow.cs:135:21:135:27 | access to local variable return : Func | -| GlobalDataFlow.cs:134:30:134:64 | SSA def(return) : Func | GlobalDataFlow.cs:139:20:139:26 | access to local variable return | -| GlobalDataFlow.cs:134:30:134:64 | SSA def(return) : Func | GlobalDataFlow.cs:139:20:139:26 | access to local variable return : Func | -| GlobalDataFlow.cs:134:40:134:40 | x : Object | GlobalDataFlow.cs:134:40:134:40 | x | -| GlobalDataFlow.cs:134:40:134:40 | x : Object | GlobalDataFlow.cs:134:40:134:40 | x : String | -| GlobalDataFlow.cs:134:40:134:40 | x : Object | GlobalDataFlow.cs:134:63:134:63 | access to parameter x | -| GlobalDataFlow.cs:134:40:134:40 | x : Object | GlobalDataFlow.cs:134:63:134:63 | access to parameter x | -| GlobalDataFlow.cs:134:40:134:40 | x : Object | GlobalDataFlow.cs:134:63:134:63 | access to parameter x : Object | -| GlobalDataFlow.cs:134:40:134:40 | x : Object | GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | -| GlobalDataFlow.cs:134:40:134:40 | x : String | GlobalDataFlow.cs:134:63:134:63 | access to parameter x | -| GlobalDataFlow.cs:134:40:134:40 | x : String | GlobalDataFlow.cs:134:63:134:63 | access to parameter x | -| GlobalDataFlow.cs:134:40:134:40 | x : String | GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | -| GlobalDataFlow.cs:134:40:134:40 | x : String | GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | -| GlobalDataFlow.cs:134:40:134:40 | x : T | GlobalDataFlow.cs:134:63:134:63 | access to parameter x | -| GlobalDataFlow.cs:134:40:134:40 | x : T | GlobalDataFlow.cs:134:63:134:63 | access to parameter x : T | -| GlobalDataFlow.cs:134:40:134:64 | (...) => ... : Func | GlobalDataFlow.cs:134:30:134:64 | SSA def(return) | -| GlobalDataFlow.cs:134:40:134:64 | (...) => ... : Func | GlobalDataFlow.cs:134:30:134:64 | SSA def(return) : Func | -| GlobalDataFlow.cs:134:40:134:64 | (...) => ... : Func | GlobalDataFlow.cs:135:21:135:27 | access to local variable return | -| GlobalDataFlow.cs:134:40:134:64 | (...) => ... : Func | GlobalDataFlow.cs:135:21:135:27 | access to local variable return : Func | -| GlobalDataFlow.cs:134:40:134:64 | (...) => ... : Func | GlobalDataFlow.cs:139:20:139:26 | access to local variable return | -| GlobalDataFlow.cs:134:40:134:64 | (...) => ... : Func | GlobalDataFlow.cs:139:20:139:26 | access to local variable return : Func | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : String | GlobalDataFlow.cs:135:21:135:34 | delegate call | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : String | GlobalDataFlow.cs:135:21:135:34 | delegate call : String | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : String | GlobalDataFlow.cs:139:20:139:36 | delegate call | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : String | GlobalDataFlow.cs:139:20:139:36 | delegate call : String | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | GlobalDataFlow.cs:135:21:135:34 | delegate call | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | GlobalDataFlow.cs:135:21:135:34 | delegate call : T | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | GlobalDataFlow.cs:139:20:139:36 | delegate call | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | GlobalDataFlow.cs:139:20:139:36 | delegate call : T | -| GlobalDataFlow.cs:134:55:134:60 | delegate creation of type Func : Func | GlobalDataFlow.cs:364:41:364:41 | f | -| GlobalDataFlow.cs:134:55:134:60 | delegate creation of type Func : Func | GlobalDataFlow.cs:364:41:364:41 | f : Func | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : Object | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : Object | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : Object | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : Object | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : Object | GlobalDataFlow.cs:364:46:364:46 | x : Object | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:364:46:364:46 | x : String | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:364:46:364:46 | x : String | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : T | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : T | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : T | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : T | GlobalDataFlow.cs:364:46:364:46 | x : T | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : Object | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : Object | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : Object | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : Object | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : Object | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : String | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : T | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : T | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : T | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : T | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : T | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | -| GlobalDataFlow.cs:135:21:135:27 | access to local variable return : Func | GlobalDataFlow.cs:139:20:139:26 | access to local variable return | -| GlobalDataFlow.cs:135:21:135:27 | access to local variable return : Func | GlobalDataFlow.cs:139:20:139:26 | access to local variable return : Func | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : Object | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : Object | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : String | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : String | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : T | GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : T | GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : T | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : T | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : T | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : T | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : T | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : T | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | GlobalDataFlow.cs:134:40:134:40 | x | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | GlobalDataFlow.cs:134:40:134:40 | x : Object | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:21:135:34 | delegate call | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | GlobalDataFlow.cs:134:40:134:40 | x | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | GlobalDataFlow.cs:134:40:134:40 | x : String | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | GlobalDataFlow.cs:135:21:135:34 | delegate call | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | GlobalDataFlow.cs:135:21:135:34 | delegate call : String | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | GlobalDataFlow.cs:134:40:134:40 | x | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | GlobalDataFlow.cs:134:40:134:40 | x : T | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | GlobalDataFlow.cs:135:21:135:34 | delegate call | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | GlobalDataFlow.cs:135:21:135:34 | delegate call : T | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : Object | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : Object | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : T | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : T | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | -| GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) : String | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) : String | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) : T | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) : T | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : String | GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : String | GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : String | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : String | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : T | GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : T | GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : T | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : T | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | GlobalDataFlow.cs:134:40:134:40 | x | -| GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | GlobalDataFlow.cs:134:40:134:40 | x : String | -| GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:20:139:36 | delegate call | -| GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:20:139:36 | delegate call : String | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : Object | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : Object | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : Object | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : Object | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : Object | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : Object | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : String | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : String | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : String | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : String | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : T | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : T | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : T | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : T | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : T | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : T | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : Object | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : Object | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : Object | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : String | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : String | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : String | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : T | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : T | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : T | -| GlobalDataFlow.cs:143:31:143:36 | delegate creation of type Func : Func | GlobalDataFlow.cs:364:41:364:41 | f | -| GlobalDataFlow.cs:143:31:143:36 | delegate creation of type Func : Func | GlobalDataFlow.cs:364:41:364:41 | f : Func | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | GlobalDataFlow.cs:364:46:364:46 | x : Object | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | GlobalDataFlow.cs:364:46:364:46 | x : String | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | GlobalDataFlow.cs:364:46:364:46 | x : T | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : Object | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : Object | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : Object | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : String | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : String | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : String | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : T | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : T | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : T | -| GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) : String | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) : String | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) : T | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) : T | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : String | GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : String | GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : String | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : String | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : T | GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : T | GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : T | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : T | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:147:30:147:35 | delegate creation of type Func : Func | GlobalDataFlow.cs:364:41:364:41 | f | -| GlobalDataFlow.cs:147:30:147:35 | delegate creation of type Func : Func | GlobalDataFlow.cs:364:41:364:41 | f : Func | -| GlobalDataFlow.cs:147:38:147:39 | "" : String | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc | -| GlobalDataFlow.cs:147:38:147:39 | "" : String | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:147:38:147:39 | "" : String | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:147:38:147:39 | "" : String | GlobalDataFlow.cs:364:46:364:46 | x : String | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : String | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : String | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : String | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : String | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : T | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : T | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : T | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : T | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:149:30:149:36 | (...) => ... : Func | GlobalDataFlow.cs:364:41:364:41 | f | -| GlobalDataFlow.cs:149:30:149:36 | (...) => ... : Func | GlobalDataFlow.cs:364:41:364:41 | f : Func | -| GlobalDataFlow.cs:149:35:149:36 | "" : String | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:149:35:149:36 | "" : String | GlobalDataFlow.cs:366:16:366:19 | delegate call : String | -| GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : Object | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : Object | GlobalDataFlow.cs:364:46:364:46 | x : Object | -| GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : String | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : String | GlobalDataFlow.cs:364:46:364:46 | x : String | -| GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : T | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : T | GlobalDataFlow.cs:364:46:364:46 | x : T | -| GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 | -| GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 | -| GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:153:13:153:25 | SSA def(sink6) : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | -| GlobalDataFlow.cs:153:13:153:25 | SSA def(sink6) : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 : String | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | GlobalDataFlow.cs:153:13:153:25 | SSA def(sink6) | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | GlobalDataFlow.cs:153:13:153:25 | SSA def(sink6) : String | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 : String | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:316:12:316:14 | this | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:316:12:316:14 | this : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:321:10:321:15 | this | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:321:10:321:15 | this : DataFlow | -| GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | -| GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 : String | -| GlobalDataFlow.cs:158:13:158:22 | SSA def(sink8) : String | GlobalDataFlow.cs:159:20:159:24 | access to local variable sink8 | -| GlobalDataFlow.cs:158:13:158:22 | SSA def(sink8) : String | GlobalDataFlow.cs:159:20:159:24 | access to local variable sink8 : String | -| GlobalDataFlow.cs:158:21:158:22 | "" : String | GlobalDataFlow.cs:158:13:158:22 | SSA def(sink8) | -| GlobalDataFlow.cs:158:21:158:22 | "" : String | GlobalDataFlow.cs:158:13:158:22 | SSA def(sink8) : String | -| GlobalDataFlow.cs:158:21:158:22 | "" : String | GlobalDataFlow.cs:159:20:159:24 | access to local variable sink8 | -| GlobalDataFlow.cs:158:21:158:22 | "" : String | GlobalDataFlow.cs:159:20:159:24 | access to local variable sink8 : String | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:326:10:326:15 | this | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:326:10:326:15 | this : DataFlow | -| GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | -| GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 : String | -| GlobalDataFlow.cs:161:13:161:31 | SSA def(sink12) : IEnumerable | GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | -| GlobalDataFlow.cs:161:13:161:31 | SSA def(sink12) : IEnumerable | GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 : IEnumerable | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | GlobalDataFlow.cs:161:13:161:31 | SSA def(sink12) | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | GlobalDataFlow.cs:161:13:161:31 | SSA def(sink12) : IEnumerable | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 : IEnumerable | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:331:25:331:32 | this | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:331:25:331:32 | this : DataFlow | -| GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 : String | -| GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) : T | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) : T | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 : T | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) : String | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 : String | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : T | GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : T | GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) : T | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : T | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : T | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 : T | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | GlobalDataFlow.cs:378:39:378:45 | tainted | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | GlobalDataFlow.cs:378:39:378:45 | tainted : String | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : T | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | GlobalDataFlow.cs:378:39:378:45 | tainted | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | GlobalDataFlow.cs:378:39:378:45 | tainted : T | -| GlobalDataFlow.cs:167:9:167:27 | SSA def(nonSink0) : String | GlobalDataFlow.cs:168:15:168:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:167:9:167:27 | SSA def(nonSink0) : String | GlobalDataFlow.cs:168:15:168:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:167:20:167:27 | call to method NonOut : String | GlobalDataFlow.cs:167:9:167:27 | SSA def(nonSink0) | -| GlobalDataFlow.cs:167:20:167:27 | call to method NonOut : String | GlobalDataFlow.cs:167:9:167:27 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:167:20:167:27 | call to method NonOut : String | GlobalDataFlow.cs:168:15:168:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:167:20:167:27 | call to method NonOut : String | GlobalDataFlow.cs:168:15:168:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:338:12:338:17 | this | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:338:12:338:17 | this : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:343:10:343:18 | this | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:343:10:343:18 | this : DataFlow | -| GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) : String | GlobalDataFlow.cs:170:15:170:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) : String | GlobalDataFlow.cs:170:15:170:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) : String | GlobalDataFlow.cs:171:23:171:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) : String | GlobalDataFlow.cs:171:23:171:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:170:15:170:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:171:23:171:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:170:15:170:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:171:23:171:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:348:10:348:18 | this | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:348:10:348:18 | this : DataFlow | -| GlobalDataFlow.cs:171:23:171:30 | SSA def(nonSink0) : String | GlobalDataFlow.cs:172:15:172:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:171:23:171:30 | SSA def(nonSink0) : String | GlobalDataFlow.cs:172:15:172:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) : String | GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) : String | GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) : String | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 | -| GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) : String | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield : IEnumerable | GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) | -| GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield : IEnumerable | GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield : IEnumerable | GlobalDataFlow.cs:173:20:173:40 | call to method First | -| GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield : IEnumerable | GlobalDataFlow.cs:173:20:173:40 | call to method First : String | -| GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield : IEnumerable | GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield : IEnumerable | GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield : IEnumerable | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 | -| GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield : IEnumerable | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:353:25:353:35 | this | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:353:25:353:35 | this : DataFlow | -| GlobalDataFlow.cs:173:20:173:40 | call to method First : String | GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) | -| GlobalDataFlow.cs:173:20:173:40 | call to method First : String | GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:173:20:173:40 | call to method First : String | GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:173:20:173:40 | call to method First : String | GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:173:20:173:40 | call to method First : String | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 | -| GlobalDataFlow.cs:173:20:173:40 | call to method First : String | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 | -| GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:175:9:175:44 | SSA def(nonSink0) : String | GlobalDataFlow.cs:176:15:176:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:175:9:175:44 | SSA def(nonSink0) : String | GlobalDataFlow.cs:176:15:176:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam : String | GlobalDataFlow.cs:175:9:175:44 | SSA def(nonSink0) | -| GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam : String | GlobalDataFlow.cs:175:9:175:44 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam : String | GlobalDataFlow.cs:176:15:176:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam : String | GlobalDataFlow.cs:176:15:176:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam | -| GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam : String | -| GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | GlobalDataFlow.cs:385:42:385:51 | nonTainted | -| GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | -| GlobalDataFlow.cs:179:22:179:48 | SSA def(out) : Func | GlobalDataFlow.cs:180:21:180:24 | access to local variable out | -| GlobalDataFlow.cs:179:22:179:48 | SSA def(out) : Func | GlobalDataFlow.cs:180:21:180:24 | access to local variable out : Func | -| GlobalDataFlow.cs:179:29:179:48 | (...) => ... : Func | GlobalDataFlow.cs:179:22:179:48 | SSA def(out) | -| GlobalDataFlow.cs:179:29:179:48 | (...) => ... : Func | GlobalDataFlow.cs:179:22:179:48 | SSA def(out) : Func | -| GlobalDataFlow.cs:179:29:179:48 | (...) => ... : Func | GlobalDataFlow.cs:180:21:180:24 | access to local variable out | -| GlobalDataFlow.cs:179:29:179:48 | (...) => ... : Func | GlobalDataFlow.cs:180:21:180:24 | access to local variable out : Func | -| GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:180:21:180:26 | delegate call | -| GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:180:21:180:26 | delegate call : String | -| GlobalDataFlow.cs:180:13:180:26 | SSA def(sink9) : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | -| GlobalDataFlow.cs:180:13:180:26 | SSA def(sink9) : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 : String | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:180:13:180:26 | SSA def(sink9) | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:180:13:180:26 | SSA def(sink9) : String | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 : String | -| GlobalDataFlow.cs:184:22:184:38 | SSA def(nonOut) : Func | GlobalDataFlow.cs:185:20:185:25 | access to local variable nonOut | -| GlobalDataFlow.cs:184:22:184:38 | SSA def(nonOut) : Func | GlobalDataFlow.cs:185:20:185:25 | access to local variable nonOut : Func | -| GlobalDataFlow.cs:184:31:184:38 | (...) => ... : Func | GlobalDataFlow.cs:184:22:184:38 | SSA def(nonOut) | -| GlobalDataFlow.cs:184:31:184:38 | (...) => ... : Func | GlobalDataFlow.cs:184:22:184:38 | SSA def(nonOut) : Func | -| GlobalDataFlow.cs:184:31:184:38 | (...) => ... : Func | GlobalDataFlow.cs:185:20:185:25 | access to local variable nonOut | -| GlobalDataFlow.cs:184:31:184:38 | (...) => ... : Func | GlobalDataFlow.cs:185:20:185:25 | access to local variable nonOut : Func | -| GlobalDataFlow.cs:184:37:184:38 | "" : String | GlobalDataFlow.cs:185:20:185:27 | delegate call | -| GlobalDataFlow.cs:184:37:184:38 | "" : String | GlobalDataFlow.cs:185:20:185:27 | delegate call : String | -| GlobalDataFlow.cs:185:9:185:27 | SSA def(nonSink0) : String | GlobalDataFlow.cs:186:15:186:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:185:9:185:27 | SSA def(nonSink0) : String | GlobalDataFlow.cs:186:15:186:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:185:20:185:27 | delegate call : String | GlobalDataFlow.cs:185:9:185:27 | SSA def(nonSink0) | -| GlobalDataFlow.cs:185:20:185:27 | delegate call : String | GlobalDataFlow.cs:185:9:185:27 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:185:20:185:27 | delegate call : String | GlobalDataFlow.cs:186:15:186:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:185:20:185:27 | delegate call : String | GlobalDataFlow.cs:186:15:186:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : Lazy | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : Lazy | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 : Lazy | -| GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 : String | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : Lazy | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 : Lazy | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : String | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 : String | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : String | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:189:22:189:48 | access to property Value | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 : String | -| GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : Lazy | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : Lazy | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 : Lazy | -| GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : String | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : String | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:193:20:193:43 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) | -| GlobalDataFlow.cs:193:20:193:43 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : Lazy | -| GlobalDataFlow.cs:193:20:193:43 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:193:20:193:43 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 : Lazy | -| GlobalDataFlow.cs:193:20:193:49 | access to property Value : String | GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) | -| GlobalDataFlow.cs:193:20:193:49 | access to property Value : String | GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:193:20:193:49 | access to property Value : String | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:193:20:193:49 | access to property Value : String | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) | -| GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:193:20:193:49 | access to property Value | -| GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:193:20:193:49 | access to property Value : String | -| GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:197:13:197:32 | SSA def(sink19) : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs:197:13:197:32 | SSA def(sink19) : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 : String | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:197:13:197:32 | SSA def(sink19) | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:197:13:197:32 | SSA def(sink19) : String | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 : String | -| GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | GlobalDataFlow.cs:415:9:415:11 | this | -| GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | GlobalDataFlow.cs:415:9:415:11 | this : DataFlow | -| GlobalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:202:15:202:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:202:15:202:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty : String | GlobalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty : String | GlobalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty : String | GlobalDataFlow.cs:202:15:202:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty : String | GlobalDataFlow.cs:202:15:202:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | GlobalDataFlow.cs:420:9:420:11 | this | -| GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | GlobalDataFlow.cs:420:9:420:11 | this : DataFlow | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:205:39:205:45 | tainted : Object | GlobalDataFlow.cs:205:39:205:45 | tainted | -| GlobalDataFlow.cs:205:39:205:45 | tainted : Object | GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | -| GlobalDataFlow.cs:205:39:205:45 | tainted : Object | GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted | -| GlobalDataFlow.cs:205:39:205:45 | tainted : Object | GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:205:39:205:45 | tainted : Object | GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted | -| GlobalDataFlow.cs:205:39:205:45 | tainted : Object | GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:205:39:205:45 | tainted : Object | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted | -| GlobalDataFlow.cs:205:39:205:45 | tainted : Object | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : Object | GlobalDataFlow.cs:205:67:205:76 | notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : Object | GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : Object | GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : Object | GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : Object | GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : Object | GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : Object | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : Object | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : Object | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : Object | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : Object | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : Object | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:208:30:208:92 | SSA def(f1) : Func | GlobalDataFlow.cs:210:37:210:38 | access to local variable f1 | -| GlobalDataFlow.cs:208:30:208:92 | SSA def(f1) : Func | GlobalDataFlow.cs:210:37:210:38 | access to local variable f1 : Func | -| GlobalDataFlow.cs:208:30:208:92 | SSA def(f1) : Func | GlobalDataFlow.cs:220:41:220:42 | access to local variable f1 | -| GlobalDataFlow.cs:208:30:208:92 | SSA def(f1) : Func | GlobalDataFlow.cs:220:41:220:42 | access to local variable f1 : Func | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : Object | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : Object | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : Object | GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : Object | GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : Object | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : Object | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:35:208:92 | (...) => ... : Func | GlobalDataFlow.cs:208:30:208:92 | SSA def(f1) | -| GlobalDataFlow.cs:208:35:208:92 | (...) => ... : Func | GlobalDataFlow.cs:208:30:208:92 | SSA def(f1) : Func | -| GlobalDataFlow.cs:208:35:208:92 | (...) => ... : Func | GlobalDataFlow.cs:210:37:210:38 | access to local variable f1 | -| GlobalDataFlow.cs:208:35:208:92 | (...) => ... : Func | GlobalDataFlow.cs:210:37:210:38 | access to local variable f1 : Func | -| GlobalDataFlow.cs:208:35:208:92 | (...) => ... : Func | GlobalDataFlow.cs:220:41:220:42 | access to local variable f1 | -| GlobalDataFlow.cs:208:35:208:92 | (...) => ... : Func | GlobalDataFlow.cs:220:41:220:42 | access to local variable f1 : Func | -| GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 | -| GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 : String | -| GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 | -| GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 : String | -| GlobalDataFlow.cs:209:66:209:90 | SSA def(f2) : Expression> | GlobalDataFlow.cs:212:37:212:38 | access to local variable f2 | -| GlobalDataFlow.cs:209:66:209:90 | SSA def(f2) : Expression> | GlobalDataFlow.cs:212:37:212:38 | access to local variable f2 : Expression> | -| GlobalDataFlow.cs:209:66:209:90 | SSA def(f2) : Expression> | GlobalDataFlow.cs:222:37:222:38 | access to local variable f2 | -| GlobalDataFlow.cs:209:66:209:90 | SSA def(f2) : Expression> | GlobalDataFlow.cs:222:37:222:38 | access to local variable f2 : Expression> | -| GlobalDataFlow.cs:209:71:209:71 | x : IQueryable | GlobalDataFlow.cs:209:71:209:71 | x | -| GlobalDataFlow.cs:209:71:209:71 | x : IQueryable | GlobalDataFlow.cs:209:71:209:71 | x : String | -| GlobalDataFlow.cs:209:71:209:71 | x : IQueryable | GlobalDataFlow.cs:209:89:209:89 | access to parameter x | -| GlobalDataFlow.cs:209:71:209:71 | x : IQueryable | GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | -| GlobalDataFlow.cs:209:71:209:71 | x : Object | GlobalDataFlow.cs:209:71:209:71 | x | -| GlobalDataFlow.cs:209:71:209:71 | x : Object | GlobalDataFlow.cs:209:71:209:71 | x : String | -| GlobalDataFlow.cs:209:71:209:71 | x : Object | GlobalDataFlow.cs:209:89:209:89 | access to parameter x | -| GlobalDataFlow.cs:209:71:209:71 | x : Object | GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | -| GlobalDataFlow.cs:209:71:209:71 | x : String | GlobalDataFlow.cs:209:89:209:89 | access to parameter x | -| GlobalDataFlow.cs:209:71:209:71 | x : String | GlobalDataFlow.cs:209:89:209:89 | access to parameter x | -| GlobalDataFlow.cs:209:71:209:71 | x : String | GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | -| GlobalDataFlow.cs:209:71:209:71 | x : String | GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | -| GlobalDataFlow.cs:209:71:209:90 | (...) => ... : Expression> | GlobalDataFlow.cs:209:66:209:90 | SSA def(f2) | -| GlobalDataFlow.cs:209:71:209:90 | (...) => ... : Expression> | GlobalDataFlow.cs:209:66:209:90 | SSA def(f2) : Expression> | -| GlobalDataFlow.cs:209:71:209:90 | (...) => ... : Expression> | GlobalDataFlow.cs:212:37:212:38 | access to local variable f2 | -| GlobalDataFlow.cs:209:71:209:90 | (...) => ... : Expression> | GlobalDataFlow.cs:212:37:212:38 | access to local variable f2 : Expression> | -| GlobalDataFlow.cs:209:71:209:90 | (...) => ... : Expression> | GlobalDataFlow.cs:222:37:222:38 | access to local variable f2 | -| GlobalDataFlow.cs:209:71:209:90 | (...) => ... : Expression> | GlobalDataFlow.cs:222:37:222:38 | access to local variable f2 : Expression> | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : String | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : String | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : String | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : String | GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : String | GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : T | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : T | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : T | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : T | GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : T | GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : String | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : String | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:298:32:298:41 | sinkParam9 | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:298:32:298:41 | sinkParam9 | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | -| GlobalDataFlow.cs:210:13:210:39 | SSA def(sink24) : IEnumerable | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 | -| GlobalDataFlow.cs:210:13:210:39 | SSA def(sink24) : IEnumerable | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 : IEnumerable | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 : String | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:210:22:210:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:210:13:210:39 | SSA def(sink24) | -| GlobalDataFlow.cs:210:22:210:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:210:13:210:39 | SSA def(sink24) : IEnumerable | -| GlobalDataFlow.cs:210:22:210:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 | -| GlobalDataFlow.cs:210:22:210:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 : IEnumerable | -| GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 : String | GlobalDataFlow.cs:210:13:210:39 | SSA def(sink24) | -| GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 : String | GlobalDataFlow.cs:210:13:210:39 | SSA def(sink24) : IEnumerable | -| GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 : String | GlobalDataFlow.cs:210:22:210:39 | call to method Select | -| GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 : String | GlobalDataFlow.cs:210:22:210:39 | call to method Select : IEnumerable | -| GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 : String | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 | -| GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 : String | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 : IEnumerable | -| GlobalDataFlow.cs:210:37:210:38 | access to local variable f1 : Func | GlobalDataFlow.cs:220:41:220:42 | access to local variable f1 | -| GlobalDataFlow.cs:210:37:210:38 | access to local variable f1 : Func | GlobalDataFlow.cs:220:41:220:42 | access to local variable f1 : Func | -| GlobalDataFlow.cs:212:13:212:39 | SSA def(sink25) : IQueryable | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 | -| GlobalDataFlow.cs:212:13:212:39 | SSA def(sink25) : IQueryable | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 : IQueryable | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:209:71:209:71 | x | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:209:71:209:71 | x : IQueryable | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : String | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:212:22:212:39 | call to method Select : IQueryable | GlobalDataFlow.cs:212:13:212:39 | SSA def(sink25) | -| GlobalDataFlow.cs:212:22:212:39 | call to method Select : IQueryable | GlobalDataFlow.cs:212:13:212:39 | SSA def(sink25) : IQueryable | -| GlobalDataFlow.cs:212:22:212:39 | call to method Select : IQueryable | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 | -| GlobalDataFlow.cs:212:22:212:39 | call to method Select : IQueryable | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 : IQueryable | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:212:13:212:39 | SSA def(sink25) | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:212:13:212:39 | SSA def(sink25) : IQueryable | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:212:22:212:39 | call to method Select | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:212:22:212:39 | call to method Select : IQueryable | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 : IQueryable | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:212:13:212:39 | SSA def(sink25) | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:212:13:212:39 | SSA def(sink25) : IQueryable | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:212:22:212:39 | call to method Select | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:212:22:212:39 | call to method Select : IQueryable | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 : IQueryable | -| GlobalDataFlow.cs:212:37:212:38 | access to local variable f2 : Expression> | GlobalDataFlow.cs:222:37:222:38 | access to local variable f2 | -| GlobalDataFlow.cs:212:37:212:38 | access to local variable f2 : Expression> | GlobalDataFlow.cs:222:37:222:38 | access to local variable f2 : Expression> | -| GlobalDataFlow.cs:214:13:214:49 | SSA def(sink26) : IEnumerable | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 | -| GlobalDataFlow.cs:214:13:214:49 | SSA def(sink26) : IEnumerable | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 : IEnumerable | -| GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 | -| GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | -| GlobalDataFlow.cs:214:22:214:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:214:13:214:49 | SSA def(sink26) | -| GlobalDataFlow.cs:214:22:214:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:214:13:214:49 | SSA def(sink26) : IEnumerable | -| GlobalDataFlow.cs:214:22:214:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 | -| GlobalDataFlow.cs:214:22:214:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 : IEnumerable | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:214:13:214:49 | SSA def(sink26) | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:214:13:214:49 | SSA def(sink26) : IEnumerable | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:214:22:214:49 | call to method Select | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:214:22:214:49 | call to method Select : IEnumerable | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 : IEnumerable | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:214:13:214:49 | SSA def(sink26) | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:214:13:214:49 | SSA def(sink26) : IEnumerable | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:214:22:214:49 | call to method Select | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:214:22:214:49 | call to method Select : IEnumerable | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 : IEnumerable | -| GlobalDataFlow.cs:218:30:218:95 | SSA def(f3) : Func | GlobalDataFlow.cs:224:37:224:38 | access to local variable f3 | -| GlobalDataFlow.cs:218:30:218:95 | SSA def(f3) : Func | GlobalDataFlow.cs:224:37:224:38 | access to local variable f3 : Func | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : IQueryable | GlobalDataFlow.cs:218:35:218:46 | nonSinkParam | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : IQueryable | GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : IQueryable | GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : IQueryable | GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : IQueryable | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : IQueryable | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : Object | GlobalDataFlow.cs:218:35:218:46 | nonSinkParam | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : Object | GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : Object | GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : Object | GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : Object | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : Object | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:35:218:95 | (...) => ... : Func | GlobalDataFlow.cs:218:30:218:95 | SSA def(f3) | -| GlobalDataFlow.cs:218:35:218:95 | (...) => ... : Func | GlobalDataFlow.cs:218:30:218:95 | SSA def(f3) : Func | -| GlobalDataFlow.cs:218:35:218:95 | (...) => ... : Func | GlobalDataFlow.cs:224:37:224:38 | access to local variable f3 | -| GlobalDataFlow.cs:218:35:218:95 | (...) => ... : Func | GlobalDataFlow.cs:224:37:224:38 | access to local variable f3 : Func | -| GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 | -| GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 : String | -| GlobalDataFlow.cs:219:66:219:92 | SSA def(f4) : Expression> | GlobalDataFlow.cs:226:37:226:38 | access to local variable f4 | -| GlobalDataFlow.cs:219:66:219:92 | SSA def(f4) : Expression> | GlobalDataFlow.cs:226:37:226:38 | access to local variable f4 : Expression> | -| GlobalDataFlow.cs:219:71:219:71 | x : IQueryable | GlobalDataFlow.cs:219:71:219:71 | x | -| GlobalDataFlow.cs:219:71:219:71 | x : IQueryable | GlobalDataFlow.cs:219:71:219:71 | x : String | -| GlobalDataFlow.cs:219:71:219:71 | x : IQueryable | GlobalDataFlow.cs:219:91:219:91 | access to parameter x | -| GlobalDataFlow.cs:219:71:219:71 | x : IQueryable | GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | -| GlobalDataFlow.cs:219:71:219:71 | x : Object | GlobalDataFlow.cs:219:71:219:71 | x | -| GlobalDataFlow.cs:219:71:219:71 | x : Object | GlobalDataFlow.cs:219:71:219:71 | x : String | -| GlobalDataFlow.cs:219:71:219:71 | x : Object | GlobalDataFlow.cs:219:91:219:91 | access to parameter x | -| GlobalDataFlow.cs:219:71:219:71 | x : Object | GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | -| GlobalDataFlow.cs:219:71:219:71 | x : String | GlobalDataFlow.cs:219:91:219:91 | access to parameter x | -| GlobalDataFlow.cs:219:71:219:71 | x : String | GlobalDataFlow.cs:219:91:219:91 | access to parameter x | -| GlobalDataFlow.cs:219:71:219:71 | x : String | GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | -| GlobalDataFlow.cs:219:71:219:71 | x : String | GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | -| GlobalDataFlow.cs:219:71:219:92 | (...) => ... : Expression> | GlobalDataFlow.cs:219:66:219:92 | SSA def(f4) | -| GlobalDataFlow.cs:219:71:219:92 | (...) => ... : Expression> | GlobalDataFlow.cs:219:66:219:92 | SSA def(f4) : Expression> | -| GlobalDataFlow.cs:219:71:219:92 | (...) => ... : Expression> | GlobalDataFlow.cs:226:37:226:38 | access to local variable f4 | -| GlobalDataFlow.cs:219:71:219:92 | (...) => ... : Expression> | GlobalDataFlow.cs:226:37:226:38 | access to local variable f4 : Expression> | -| GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : String | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 | -| GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : String | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | -| GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : T | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 | -| GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : T | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | -| GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck | -| GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck | -| GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : String | -| GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : String | -| GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | GlobalDataFlow.cs:310:34:310:45 | nonSinkParam | -| GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | GlobalDataFlow.cs:310:34:310:45 | nonSinkParam | -| GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : String | -| GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : String | -| GlobalDataFlow.cs:220:13:220:43 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:221:15:221:21 | access to local variable nonSink | -| GlobalDataFlow.cs:220:13:220:43 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:221:15:221:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 : String | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:220:23:220:43 | call to method Select : IEnumerable | GlobalDataFlow.cs:220:13:220:43 | SSA def(nonSink) | -| GlobalDataFlow.cs:220:23:220:43 | call to method Select : IEnumerable | GlobalDataFlow.cs:220:13:220:43 | SSA def(nonSink) : IEnumerable | -| GlobalDataFlow.cs:220:23:220:43 | call to method Select : IEnumerable | GlobalDataFlow.cs:221:15:221:21 | access to local variable nonSink | -| GlobalDataFlow.cs:220:23:220:43 | call to method Select : IEnumerable | GlobalDataFlow.cs:221:15:221:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 : String | GlobalDataFlow.cs:220:13:220:43 | SSA def(nonSink) | -| GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 : String | GlobalDataFlow.cs:220:13:220:43 | SSA def(nonSink) : IEnumerable | -| GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 : String | GlobalDataFlow.cs:220:23:220:43 | call to method Select | -| GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 : String | GlobalDataFlow.cs:220:23:220:43 | call to method Select : IEnumerable | -| GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 : String | GlobalDataFlow.cs:221:15:221:21 | access to local variable nonSink | -| GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 : String | GlobalDataFlow.cs:221:15:221:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink | -| GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IQueryable | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink | -| GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IQueryable | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IQueryable | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:209:71:209:71 | x | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:209:71:209:71 | x : IQueryable | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) | -| GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IQueryable | -| GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink | -| GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IQueryable | -| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) | -| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IQueryable | -| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:222:19:222:39 | call to method Select | -| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable | -| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink | -| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IQueryable | -| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) | -| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IQueryable | -| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:222:19:222:39 | call to method Select | -| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable | -| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink | -| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IQueryable | -| GlobalDataFlow.cs:224:9:224:39 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:225:15:225:21 | access to local variable nonSink | -| GlobalDataFlow.cs:224:9:224:39 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:225:15:225:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:218:35:218:46 | nonSinkParam | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : IQueryable | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 : String | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:224:19:224:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:224:9:224:39 | SSA def(nonSink) | -| GlobalDataFlow.cs:224:19:224:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:224:9:224:39 | SSA def(nonSink) : IEnumerable | -| GlobalDataFlow.cs:224:19:224:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:225:15:225:21 | access to local variable nonSink | -| GlobalDataFlow.cs:224:19:224:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:225:15:225:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 : String | GlobalDataFlow.cs:224:9:224:39 | SSA def(nonSink) | -| GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 : String | GlobalDataFlow.cs:224:9:224:39 | SSA def(nonSink) : IEnumerable | -| GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 : String | GlobalDataFlow.cs:224:19:224:39 | call to method Select | -| GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 : String | GlobalDataFlow.cs:224:19:224:39 | call to method Select : IEnumerable | -| GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 : String | GlobalDataFlow.cs:225:15:225:21 | access to local variable nonSink | -| GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 : String | GlobalDataFlow.cs:225:15:225:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink | -| GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IQueryable | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink | -| GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IQueryable | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IQueryable | -| GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:219:71:219:71 | x | -| GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:219:71:219:71 | x : IQueryable | -| GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 | -| GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | -| GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted | -| GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) | -| GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IQueryable | -| GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink | -| GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IQueryable | -| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) | -| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IQueryable | -| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:226:19:226:39 | call to method Select | -| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable | -| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink | -| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IQueryable | -| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) | -| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IQueryable | -| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:226:19:226:39 | call to method Select | -| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable | -| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink | -| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IQueryable | -| GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink | -| GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 | -| GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | -| GlobalDataFlow.cs:228:19:228:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) | -| GlobalDataFlow.cs:228:19:228:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) : IEnumerable | -| GlobalDataFlow.cs:228:19:228:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink | -| GlobalDataFlow.cs:228:19:228:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) | -| GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) : IEnumerable | -| GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:228:19:228:49 | call to method Select | -| GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:228:19:228:49 | call to method Select : IEnumerable | -| GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink | -| GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) | -| GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) : IEnumerable | -| GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:228:19:228:49 | call to method Select | -| GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:228:19:228:49 | call to method Select : IEnumerable | -| GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink | -| GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : Object | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : Object | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : Object | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : Object | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : Object | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : Object | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : Object | GlobalDataFlow.cs:240:26:240:35 | sinkParam1 | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : Object | GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : T | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : Object | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : Object | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 : T | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : String | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : String | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 : String | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : T | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : T | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 : T | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : Object | GlobalDataFlow.cs:245:26:245:35 | sinkParam3 | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : Object | GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : T | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : Object | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : Object | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 : T | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : String | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : String | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 : String | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : T | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : T | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : T | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 : T | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : T | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 : T | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : Object | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : Object | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : T | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : Object | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : Object | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 : T | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 : String | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : T | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : T | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : T | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 : T | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : T | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 : T | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : Object | GlobalDataFlow.cs:255:26:255:35 | sinkParam5 | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : Object | GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : T | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : Object | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : Object | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 : T | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 : String | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : T | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : T | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 : T | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : Object | GlobalDataFlow.cs:260:26:260:35 | sinkParam6 | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : Object | GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : T | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : Object | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : Object | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 : T | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 : String | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : T | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : T | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 : T | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : Object | GlobalDataFlow.cs:265:26:265:35 | sinkParam7 | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : Object | GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : T | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : Object | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : Object | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 : T | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 : String | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : T | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : T | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 : T | -| GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : Object | GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 | -| GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : Object | GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : T | -| GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : Object | GlobalDataFlow.cs:272:15:272:27 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : Object | GlobalDataFlow.cs:272:15:272:27 | access to parameter nonSinkParam0 : T | -| GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : String | GlobalDataFlow.cs:272:15:272:27 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : String | GlobalDataFlow.cs:272:15:272:27 | access to parameter nonSinkParam0 : String | -| GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : T | GlobalDataFlow.cs:272:15:272:27 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : T | GlobalDataFlow.cs:272:15:272:27 | access to parameter nonSinkParam0 : T | -| GlobalDataFlow.cs:275:26:275:26 | x : Object | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:275:26:275:26 | x : Object | GlobalDataFlow.cs:275:26:275:26 | x : T | -| GlobalDataFlow.cs:275:26:275:26 | x : Object | GlobalDataFlow.cs:277:37:277:37 | access to parameter x | -| GlobalDataFlow.cs:275:26:275:26 | x : Object | GlobalDataFlow.cs:277:37:277:37 | access to parameter x | -| GlobalDataFlow.cs:275:26:275:26 | x : Object | GlobalDataFlow.cs:277:37:277:37 | access to parameter x : Object | -| GlobalDataFlow.cs:275:26:275:26 | x : Object | GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | -| GlobalDataFlow.cs:275:26:275:26 | x : String | GlobalDataFlow.cs:277:37:277:37 | access to parameter x | -| GlobalDataFlow.cs:275:26:275:26 | x : String | GlobalDataFlow.cs:277:37:277:37 | access to parameter x : String | -| GlobalDataFlow.cs:275:26:275:26 | x : T | GlobalDataFlow.cs:277:37:277:37 | access to parameter x | -| GlobalDataFlow.cs:275:26:275:26 | x : T | GlobalDataFlow.cs:277:37:277:37 | access to parameter x | -| GlobalDataFlow.cs:275:26:275:26 | x : T | GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | -| GlobalDataFlow.cs:275:26:275:26 | x : T | GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:16:278:16 | (...) ... : Object | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : Object | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : Object | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:16:278:16 | (...) ... : String | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : String | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : String | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:16:278:16 | (...) ... : Object | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : Object | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : Object | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:16:278:16 | (...) ... : String | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : String | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : String | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | -| GlobalDataFlow.cs:277:27:277:28 | x0 : Object | GlobalDataFlow.cs:277:27:277:28 | x0 | -| GlobalDataFlow.cs:277:27:277:28 | x0 : Object | GlobalDataFlow.cs:277:27:277:28 | x0 : T | -| GlobalDataFlow.cs:277:27:277:28 | x0 : Object | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 | -| GlobalDataFlow.cs:277:27:277:28 | x0 : Object | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 | -| GlobalDataFlow.cs:277:27:277:28 | x0 : Object | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : Object | -| GlobalDataFlow.cs:277:27:277:28 | x0 : Object | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : T | -| GlobalDataFlow.cs:277:27:277:28 | x0 : String | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 | -| GlobalDataFlow.cs:277:27:277:28 | x0 : String | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : String | -| GlobalDataFlow.cs:277:27:277:28 | x0 : T | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 | -| GlobalDataFlow.cs:277:27:277:28 | x0 : T | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 | -| GlobalDataFlow.cs:277:27:277:28 | x0 : T | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : T | -| GlobalDataFlow.cs:277:27:277:28 | x0 : T | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : T | -| GlobalDataFlow.cs:277:27:277:34 | (...) => ... : Func | GlobalDataFlow.cs:364:41:364:41 | f | -| GlobalDataFlow.cs:277:27:277:34 | (...) => ... : Func | GlobalDataFlow.cs:364:41:364:41 | f : Func | -| GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : T | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : T | GlobalDataFlow.cs:366:16:366:19 | delegate call : T | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : Object | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : Object | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : Object | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : Object | GlobalDataFlow.cs:364:46:364:46 | x : Object | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : String | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : String | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : String | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : String | GlobalDataFlow.cs:364:46:364:46 | x : String | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:364:46:364:46 | x : T | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:364:46:364:46 | x : T | -| GlobalDataFlow.cs:278:16:278:16 | (...) ... : Object | GlobalDataFlow.cs:278:16:278:24 | ... == ... | -| GlobalDataFlow.cs:278:16:278:16 | (...) ... : Object | GlobalDataFlow.cs:278:16:278:24 | ... == ... | -| GlobalDataFlow.cs:278:16:278:16 | (...) ... : Object | GlobalDataFlow.cs:278:16:278:24 | ... == ... : Boolean | -| GlobalDataFlow.cs:278:16:278:16 | (...) ... : Object | GlobalDataFlow.cs:278:16:278:24 | ... == ... : Boolean | -| GlobalDataFlow.cs:278:16:278:16 | (...) ... : String | GlobalDataFlow.cs:278:16:278:24 | ... == ... | -| GlobalDataFlow.cs:278:16:278:16 | (...) ... : String | GlobalDataFlow.cs:278:16:278:24 | ... == ... : Boolean | -| GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | GlobalDataFlow.cs:278:16:278:24 | ... == ... | -| GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | GlobalDataFlow.cs:278:16:278:24 | ... == ... | -| GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | GlobalDataFlow.cs:278:16:278:24 | ... == ... : Boolean | -| GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | GlobalDataFlow.cs:278:16:278:24 | ... == ... : Boolean | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | GlobalDataFlow.cs:278:16:278:16 | (...) ... : Object | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : Object | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : Object | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | GlobalDataFlow.cs:278:16:278:16 | (...) ... : String | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : String | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : String | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:70:21:70:46 | call to method Return | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : T | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:100:24:100:33 | call to method Return | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : T | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:366:16:366:19 | delegate call : T | -| GlobalDataFlow.cs:278:28:278:37 | default(...) : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:28:278:37 | default(...) : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : Object | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : String | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:281:32:281:32 | x : T | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : Object | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:283:13:283:13 | access to parameter x | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:283:13:283:13 | access to parameter x | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:283:13:283:13 | access to parameter x : Object | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | -| GlobalDataFlow.cs:281:32:281:32 | x : String | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:281:32:281:32 | x : String | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : String | -| GlobalDataFlow.cs:281:32:281:32 | x : String | GlobalDataFlow.cs:283:13:283:13 | access to parameter x | -| GlobalDataFlow.cs:281:32:281:32 | x : String | GlobalDataFlow.cs:283:13:283:13 | access to parameter x : String | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:13:283:13 | access to parameter x | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:13:283:13 | access to parameter x | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | -| GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) | -| GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : T | -| GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : Object | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : Object | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : Object | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : String | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : String | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : String | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | -| GlobalDataFlow.cs:284:9:284:22 | SSA def(z) : T | GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) | -| GlobalDataFlow.cs:284:9:284:22 | SSA def(z) : T | GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:284:13:284:22 | default(...) : T | GlobalDataFlow.cs:284:9:284:22 | SSA def(z) | -| GlobalDataFlow.cs:284:13:284:22 | default(...) : T | GlobalDataFlow.cs:284:9:284:22 | SSA def(z) : T | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:287:32:287:32 | x : T | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : Object | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:289:13:289:13 | access to parameter x | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:289:13:289:13 | access to parameter x | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:289:13:289:13 | access to parameter x : Object | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | -| GlobalDataFlow.cs:287:32:287:32 | x : String | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:287:32:287:32 | x : String | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : String | -| GlobalDataFlow.cs:287:32:287:32 | x : String | GlobalDataFlow.cs:289:13:289:13 | access to parameter x | -| GlobalDataFlow.cs:287:32:287:32 | x : String | GlobalDataFlow.cs:289:13:289:13 | access to parameter x : String | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:13:289:13 | access to parameter x | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:13:289:13 | access to parameter x | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | -| GlobalDataFlow.cs:287:50:287:50 | z : Object | GlobalDataFlow.cs:287:50:287:50 | z | -| GlobalDataFlow.cs:287:50:287:50 | z : Object | GlobalDataFlow.cs:287:50:287:50 | z : T | -| GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) | -| GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | -| GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) | -| GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : T | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : Object | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : Object | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : Object | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : String | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : String | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : String | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : IEnumerable | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : IEnumerable | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : IEnumerable | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : IEnumerable | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : IEnumerable | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : IEnumerable | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : Object | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : Object | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : Object | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : Object | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : Object | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : Object | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : Object | GlobalDataFlow.cs:298:32:298:41 | sinkParam9 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : Object | GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : T | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : Object | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : Object | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : T | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : Object | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : Object | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : T | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : String | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : String | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : T | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : T | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : T | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : T | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : T | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : T | -| GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : String | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : String | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : String | -| GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : T | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : T | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : T | -| GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : T | GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 | -| GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : T | GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : T | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : Object | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : Object | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : Object | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : Object | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : Object | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : Object | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : Object | GlobalDataFlow.cs:310:34:310:45 | nonSinkParam | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : Object | GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : T | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : Object | GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : Object | GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : T | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : Object | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : Object | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : T | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : String | GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : String | GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : String | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : String | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : T | GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : T | GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : T | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : T | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : T | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : T | -| GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : T | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : T | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : T | -| GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : T | GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck | -| GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : T | GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : T | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:323:9:323:26 | SSA def(x) : String | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) | -| GlobalDataFlow.cs:323:9:323:26 | SSA def(x) : String | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | -| GlobalDataFlow.cs:323:13:323:26 | "taint source" : String | GlobalDataFlow.cs:323:9:323:26 | SSA def(x) | -| GlobalDataFlow.cs:323:13:323:26 | "taint source" : String | GlobalDataFlow.cs:323:9:323:26 | SSA def(x) : String | -| GlobalDataFlow.cs:328:9:328:26 | SSA def(x) : String | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) | -| GlobalDataFlow.cs:328:9:328:26 | SSA def(x) : String | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | -| GlobalDataFlow.cs:328:13:328:26 | "taint source" : String | GlobalDataFlow.cs:328:9:328:26 | SSA def(x) | -| GlobalDataFlow.cs:328:13:328:26 | "taint source" : String | GlobalDataFlow.cs:328:9:328:26 | SSA def(x) : String | -| GlobalDataFlow.cs:333:22:333:23 | "" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | -| GlobalDataFlow.cs:333:22:333:23 | "" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | -| GlobalDataFlow.cs:333:22:333:23 | "" : String | GlobalDataFlow.cs:333:22:333:23 | "" | -| GlobalDataFlow.cs:333:22:333:23 | "" : String | GlobalDataFlow.cs:333:22:333:23 | "" : IEnumerable | -| GlobalDataFlow.cs:334:22:334:35 | "taint source" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | -| GlobalDataFlow.cs:334:22:334:35 | "taint source" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | -| GlobalDataFlow.cs:334:22:334:35 | "taint source" : String | GlobalDataFlow.cs:334:22:334:35 | "taint source" | -| GlobalDataFlow.cs:334:22:334:35 | "taint source" : String | GlobalDataFlow.cs:334:22:334:35 | "taint source" : IEnumerable | -| GlobalDataFlow.cs:335:22:335:23 | "" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | -| GlobalDataFlow.cs:335:22:335:23 | "" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | -| GlobalDataFlow.cs:335:22:335:23 | "" : String | GlobalDataFlow.cs:335:22:335:23 | "" | -| GlobalDataFlow.cs:335:22:335:23 | "" : String | GlobalDataFlow.cs:335:22:335:23 | "" : IEnumerable | -| GlobalDataFlow.cs:340:16:340:17 | "" : String | GlobalDataFlow.cs:167:20:167:27 | call to method NonOut | -| GlobalDataFlow.cs:340:16:340:17 | "" : String | GlobalDataFlow.cs:167:20:167:27 | call to method NonOut : String | -| GlobalDataFlow.cs:340:16:340:17 | "" : String | GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:340:16:340:17 | "" : String | GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:345:9:345:14 | SSA def(x) : String | GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) | -| GlobalDataFlow.cs:345:9:345:14 | SSA def(x) : String | GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:345:13:345:14 | "" : String | GlobalDataFlow.cs:345:9:345:14 | SSA def(x) | -| GlobalDataFlow.cs:345:13:345:14 | "" : String | GlobalDataFlow.cs:345:9:345:14 | SSA def(x) : String | -| GlobalDataFlow.cs:350:9:350:14 | SSA def(x) : String | GlobalDataFlow.cs:171:23:171:30 | SSA def(nonSink0) | -| GlobalDataFlow.cs:350:9:350:14 | SSA def(x) : String | GlobalDataFlow.cs:171:23:171:30 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:350:13:350:14 | "" : String | GlobalDataFlow.cs:350:9:350:14 | SSA def(x) | -| GlobalDataFlow.cs:350:13:350:14 | "" : String | GlobalDataFlow.cs:350:9:350:14 | SSA def(x) : String | -| GlobalDataFlow.cs:355:22:355:23 | "" : IEnumerable | GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield | -| GlobalDataFlow.cs:355:22:355:23 | "" : IEnumerable | GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield : IEnumerable | -| GlobalDataFlow.cs:355:22:355:23 | "" : String | GlobalDataFlow.cs:355:22:355:23 | "" | -| GlobalDataFlow.cs:355:22:355:23 | "" : String | GlobalDataFlow.cs:355:22:355:23 | "" : IEnumerable | -| GlobalDataFlow.cs:356:22:356:23 | "" : IEnumerable | GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield | -| GlobalDataFlow.cs:356:22:356:23 | "" : IEnumerable | GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield : IEnumerable | -| GlobalDataFlow.cs:356:22:356:23 | "" : String | GlobalDataFlow.cs:356:22:356:23 | "" | -| GlobalDataFlow.cs:356:22:356:23 | "" : String | GlobalDataFlow.cs:356:22:356:23 | "" : IEnumerable | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a : Action | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a : Action | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a : Action | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a : Action | -| GlobalDataFlow.cs:359:36:359:36 | a : Object | GlobalDataFlow.cs:359:36:359:36 | a | -| GlobalDataFlow.cs:359:36:359:36 | a : Object | GlobalDataFlow.cs:359:36:359:36 | a : Action | -| GlobalDataFlow.cs:359:36:359:36 | a : Object | GlobalDataFlow.cs:361:9:361:9 | access to parameter a | -| GlobalDataFlow.cs:359:36:359:36 | a : Object | GlobalDataFlow.cs:361:9:361:9 | access to parameter a : Action | -| GlobalDataFlow.cs:359:41:359:41 | x : Object | GlobalDataFlow.cs:359:41:359:41 | x | -| GlobalDataFlow.cs:359:41:359:41 | x : Object | GlobalDataFlow.cs:359:41:359:41 | x : T | -| GlobalDataFlow.cs:359:41:359:41 | x : Object | GlobalDataFlow.cs:361:11:361:11 | access to parameter x | -| GlobalDataFlow.cs:359:41:359:41 | x : Object | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | -| GlobalDataFlow.cs:359:41:359:41 | x : T | GlobalDataFlow.cs:361:11:361:11 | access to parameter x | -| GlobalDataFlow.cs:359:41:359:41 | x : T | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:53:15:53:15 | x | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:53:15:53:15 | x : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:245:26:245:35 | sinkParam3 | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | GlobalDataFlow.cs:53:15:53:15 | x | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | GlobalDataFlow.cs:53:15:53:15 | x : T | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : T | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | GlobalDataFlow.cs:245:26:245:35 | sinkParam3 | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : T | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:41:364:41 | f : Object | GlobalDataFlow.cs:364:41:364:41 | f | -| GlobalDataFlow.cs:364:41:364:41 | f : Object | GlobalDataFlow.cs:364:41:364:41 | f : Func | -| GlobalDataFlow.cs:364:41:364:41 | f : Object | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Object | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:364:46:364:46 | x : T | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : String | GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : String | GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:275:26:275:26 | x : Object | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:275:26:275:26 | x : Object | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:277:27:277:28 | x0 | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:277:27:277:28 | x0 : Object | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:366:16:366:19 | delegate call : Object | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:366:16:366:19 | delegate call : Object | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:366:16:366:19 | delegate call : Object | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:277:27:277:28 | x0 | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:277:27:277:28 | x0 : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:275:26:275:26 | x : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:275:26:275:26 | x : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:275:26:275:26 | x : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:277:27:277:28 | x0 | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:277:27:277:28 | x0 | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:277:27:277:28 | x0 : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:277:27:277:28 | x0 : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call : T | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a : MyDelegate | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a : MyDelegate | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a : MyDelegate | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a : MyDelegate | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a : MyDelegate | -| GlobalDataFlow.cs:373:42:373:42 | a : Object | GlobalDataFlow.cs:373:42:373:42 | a | -| GlobalDataFlow.cs:373:42:373:42 | a : Object | GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | -| GlobalDataFlow.cs:373:42:373:42 | a : Object | GlobalDataFlow.cs:375:9:375:9 | access to parameter a | -| GlobalDataFlow.cs:373:42:373:42 | a : Object | GlobalDataFlow.cs:375:9:375:9 | access to parameter a : MyDelegate | -| GlobalDataFlow.cs:373:52:373:52 | x : Object | GlobalDataFlow.cs:373:52:373:52 | x | -| GlobalDataFlow.cs:373:52:373:52 | x : Object | GlobalDataFlow.cs:373:52:373:52 | x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : Object | GlobalDataFlow.cs:375:11:375:11 | access to parameter x | -| GlobalDataFlow.cs:373:52:373:52 | x : Object | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:255:26:255:35 | sinkParam5 | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:255:26:255:35 | sinkParam5 | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:260:26:260:35 | sinkParam6 | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:260:26:260:35 | sinkParam6 | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : Object | GlobalDataFlow.cs:378:39:378:45 | tainted | -| GlobalDataFlow.cs:378:39:378:45 | tainted : Object | GlobalDataFlow.cs:378:39:378:45 | tainted : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : Object | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:378:39:378:45 | tainted : Object | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : Object | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted | -| GlobalDataFlow.cs:378:39:378:45 | tainted : Object | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : Object | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : Object | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : Object | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : Object | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : T | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : T | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : T | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : T | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : T | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : T | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : T | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : T | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : T | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : T | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : T | -| GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam | -| GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : Object | GlobalDataFlow.cs:385:42:385:51 | nonTainted | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : Object | GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : Object | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : Object | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : Object | GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : Object | GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : Object | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : Object | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : Object | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : Object | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam | -| GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam : String | -| GlobalDataFlow.cs:398:62:398:63 | "" : String | GlobalDataFlow.cs:32:15:32:35 | access to property NonSinkProperty1 | -| GlobalDataFlow.cs:398:62:398:63 | "" : String | GlobalDataFlow.cs:32:15:32:35 | access to property NonSinkProperty1 : String | -| GlobalDataFlow.cs:404:9:404:11 | value : Object | GlobalDataFlow.cs:404:9:404:11 | value | -| GlobalDataFlow.cs:404:9:404:11 | value : Object | GlobalDataFlow.cs:404:9:404:11 | value : String | -| GlobalDataFlow.cs:404:9:404:11 | value : Object | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) | -| GlobalDataFlow.cs:404:9:404:11 | value : Object | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | -| GlobalDataFlow.cs:404:9:404:11 | value : Object | GlobalDataFlow.cs:404:28:404:32 | access to parameter value | -| GlobalDataFlow.cs:404:9:404:11 | value : Object | GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | -| GlobalDataFlow.cs:404:9:404:11 | value : Object | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:9:404:11 | value : Object | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:28:404:32 | access to parameter value | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:28:404:32 | access to parameter value | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:410:9:410:11 | value : Object | GlobalDataFlow.cs:410:9:410:11 | value | -| GlobalDataFlow.cs:410:9:410:11 | value : Object | GlobalDataFlow.cs:410:9:410:11 | value : String | -| GlobalDataFlow.cs:410:9:410:11 | value : Object | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:410:9:410:11 | value : Object | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:410:9:410:11 | value : Object | GlobalDataFlow.cs:410:30:410:34 | access to parameter value | -| GlobalDataFlow.cs:410:9:410:11 | value : Object | GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | -| GlobalDataFlow.cs:410:9:410:11 | value : Object | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:9:410:11 | value : Object | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:30:410:34 | access to parameter value | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:30:410:34 | access to parameter value | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:415:22:415:35 | "taint source" : String | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty | -| GlobalDataFlow.cs:415:22:415:35 | "taint source" : String | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | -| GlobalDataFlow.cs:420:22:420:23 | "" : String | GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty | -| GlobalDataFlow.cs:420:22:420:23 | "" : String | GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty : String | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:27:429:27 | access to parameter e | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:27:429:27 | access to parameter e | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:27:429:27 | access to parameter e | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:426:71:426:71 | e : Object | GlobalDataFlow.cs:426:71:426:71 | e | -| GlobalDataFlow.cs:426:71:426:71 | e : Object | GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | -| GlobalDataFlow.cs:426:71:426:71 | e : Object | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) | -| GlobalDataFlow.cs:426:71:426:71 | e : Object | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | -| GlobalDataFlow.cs:426:71:426:71 | e : Object | GlobalDataFlow.cs:429:27:429:27 | access to parameter e | -| GlobalDataFlow.cs:426:71:426:71 | e : Object | GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | -| GlobalDataFlow.cs:426:71:426:71 | e : Object | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:426:71:426:71 | e : Object | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:429:27:429:27 | access to parameter e | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:429:27:429:27 | access to parameter e | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:429:27:429:27 | access to parameter e : String[] | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:429:27:429:27 | access to parameter e : String[] | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:426:85:426:85 | f : Func | GlobalDataFlow.cs:431:44:431:44 | access to parameter f | -| GlobalDataFlow.cs:426:85:426:85 | f : Func | GlobalDataFlow.cs:431:44:431:44 | access to parameter f | -| GlobalDataFlow.cs:426:85:426:85 | f : Func | GlobalDataFlow.cs:431:44:431:44 | access to parameter f : Func | -| GlobalDataFlow.cs:426:85:426:85 | f : Func | GlobalDataFlow.cs:431:44:431:44 | access to parameter f : Func | -| GlobalDataFlow.cs:426:85:426:85 | f : Func | GlobalDataFlow.cs:431:44:431:44 | access to parameter f | -| GlobalDataFlow.cs:426:85:426:85 | f : Func | GlobalDataFlow.cs:431:44:431:44 | access to parameter f : Func | -| GlobalDataFlow.cs:426:85:426:85 | f : Object | GlobalDataFlow.cs:426:85:426:85 | f | -| GlobalDataFlow.cs:426:85:426:85 | f : Object | GlobalDataFlow.cs:426:85:426:85 | f : Func | -| GlobalDataFlow.cs:426:85:426:85 | f : Object | GlobalDataFlow.cs:431:44:431:44 | access to parameter f | -| GlobalDataFlow.cs:426:85:426:85 | f : Object | GlobalDataFlow.cs:431:44:431:44 | access to parameter f : Func | -| GlobalDataFlow.cs:428:13:428:17 | SSA def(i) : Int32 | GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) | -| GlobalDataFlow.cs:428:13:428:17 | SSA def(i) : Int32 | GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) : Int32 | -| GlobalDataFlow.cs:428:13:428:17 | SSA def(i) : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i | -| GlobalDataFlow.cs:428:13:428:17 | SSA def(i) : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i : Int32 | -| GlobalDataFlow.cs:428:17:428:17 | 0 : Int32 | GlobalDataFlow.cs:428:13:428:17 | SSA def(i) | -| GlobalDataFlow.cs:428:17:428:17 | 0 : Int32 | GlobalDataFlow.cs:428:13:428:17 | SSA def(i) : Int32 | -| GlobalDataFlow.cs:428:17:428:17 | 0 : Int32 | GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) | -| GlobalDataFlow.cs:428:17:428:17 | 0 : Int32 | GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) : Int32 | -| GlobalDataFlow.cs:428:17:428:17 | 0 : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i | -| GlobalDataFlow.cs:428:17:428:17 | 0 : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i : Int32 | -| GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i | -| GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i : Int32 | -| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : String[] | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : String[] | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : String[] | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : String[] | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : String[] | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : String[] | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : String[] | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : String[] | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:431:17:431:19 | SSA def(i) : Int32 | GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) | -| GlobalDataFlow.cs:431:17:431:19 | SSA def(i) : Int32 | GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) : Int32 | -| GlobalDataFlow.cs:431:17:431:19 | SSA def(i) : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i | -| GlobalDataFlow.cs:431:17:431:19 | SSA def(i) : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i : Int32 | -| GlobalDataFlow.cs:431:17:431:23 | ... % ... : Int32 | GlobalDataFlow.cs:431:17:431:28 | ... == ... | -| GlobalDataFlow.cs:431:17:431:23 | ... % ... : Int32 | GlobalDataFlow.cs:431:17:431:28 | ... == ... : Boolean | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : String | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : String | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : String | GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : String | GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:80:79:80:79 | x | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:80:79:80:79 | x | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:80:79:80:79 | x | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:80:79:80:79 | x : T | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:80:79:80:79 | x : T | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:80:79:80:79 | x : T | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:112:84:112:84 | x | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:112:84:112:84 | x | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:112:84:112:84 | x | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:112:84:112:84 | x : T | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:112:84:112:84 | x : T | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:112:84:112:84 | x : T | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : T | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : T | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : T | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : T | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : T | -| Splitting.cs:3:18:3:18 | b : Boolean | Splitting.cs:5:13:5:13 | access to parameter b | -| Splitting.cs:3:18:3:18 | b : Boolean | Splitting.cs:5:13:5:13 | access to parameter b : Boolean | -| Splitting.cs:3:18:3:18 | b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): false] access to parameter b | -| Splitting.cs:3:18:3:18 | b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): false] access to parameter b : Boolean | -| Splitting.cs:3:18:3:18 | b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): true] access to parameter b | -| Splitting.cs:3:18:3:18 | b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): true] access to parameter b : Boolean | -| Splitting.cs:3:18:3:18 | b : Object | Splitting.cs:3:18:3:18 | b | -| Splitting.cs:3:18:3:18 | b : Object | Splitting.cs:3:18:3:18 | b : Boolean | -| Splitting.cs:3:18:3:18 | b : Object | Splitting.cs:5:13:5:13 | access to parameter b | -| Splitting.cs:3:18:3:18 | b : Object | Splitting.cs:5:13:5:13 | access to parameter b : Boolean | -| Splitting.cs:3:18:3:18 | b : Object | Splitting.cs:10:13:10:13 | [b (line 3): false] access to parameter b | -| Splitting.cs:3:18:3:18 | b : Object | Splitting.cs:10:13:10:13 | [b (line 3): false] access to parameter b : Boolean | -| Splitting.cs:3:18:3:18 | b : Object | Splitting.cs:10:13:10:13 | [b (line 3): true] access to parameter b | -| Splitting.cs:3:18:3:18 | b : Object | Splitting.cs:10:13:10:13 | [b (line 3): true] access to parameter b : Boolean | -| Splitting.cs:3:28:3:34 | tainted : Object | Splitting.cs:3:28:3:34 | tainted | -| Splitting.cs:3:28:3:34 | tainted : Object | Splitting.cs:3:28:3:34 | tainted : String | -| Splitting.cs:3:28:3:34 | tainted : Object | Splitting.cs:6:17:6:23 | [b (line 3): true] access to parameter tainted | -| Splitting.cs:3:28:3:34 | tainted : Object | Splitting.cs:6:17:6:23 | [b (line 3): true] access to parameter tainted : String | -| Splitting.cs:3:28:3:34 | tainted : Object | Splitting.cs:6:17:6:31 | [b (line 3): true] ... == ... | -| Splitting.cs:3:28:3:34 | tainted : Object | Splitting.cs:6:17:6:31 | [b (line 3): true] ... == ... : Boolean | -| Splitting.cs:3:28:3:34 | tainted : Object | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted | -| Splitting.cs:3:28:3:34 | tainted : Object | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | -| Splitting.cs:3:28:3:34 | tainted : Object | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | -| Splitting.cs:3:28:3:34 | tainted : Object | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | -| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:6:17:6:23 | [b (line 3): true] access to parameter tainted | -| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:6:17:6:23 | [b (line 3): true] access to parameter tainted : String | -| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:6:17:6:31 | [b (line 3): true] ... == ... | -| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:6:17:6:31 | [b (line 3): true] ... == ... : Boolean | -| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted | -| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | -| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | -| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | -| Splitting.cs:5:13:5:13 | access to parameter b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): false] access to parameter b | -| Splitting.cs:5:13:5:13 | access to parameter b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): false] access to parameter b : Boolean | -| Splitting.cs:5:13:5:13 | access to parameter b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): true] access to parameter b | -| Splitting.cs:5:13:5:13 | access to parameter b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): true] access to parameter b : Boolean | -| Splitting.cs:6:17:6:23 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:6:17:6:31 | [b (line 3): true] ... == ... | -| Splitting.cs:6:17:6:23 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:6:17:6:31 | [b (line 3): true] ... == ... : Boolean | -| Splitting.cs:6:17:6:23 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | -| Splitting.cs:6:17:6:23 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | -| Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | -| Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x : String | -| Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) : T | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | -| Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) : T | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x : T | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : String | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : String | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : String | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : String | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : String | Splitting.cs:11:19:11:19 | access to local variable x : String | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : T | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : T | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : T | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : T | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : T | Splitting.cs:11:19:11:19 | access to local variable x : T | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) : String | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x : String | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : T | Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : T | Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) : T | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : T | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : T | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x : T | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : String | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : String | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:11:19:11:19 | access to local variable x : String | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : T | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : T | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | Splitting.cs:11:19:11:19 | access to local variable x : T | -| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | -| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | -| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | Splitting.cs:16:26:16:26 | x : String | -| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | -| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | -| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:16:26:16:26 | x : String | -| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : String | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : String | Splitting.cs:11:19:11:19 | access to local variable x : String | -| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : T | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : T | Splitting.cs:11:19:11:19 | access to local variable x : T | -| Splitting.cs:16:26:16:26 | x : Object | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:16:26:16:26 | x : Object | Splitting.cs:16:26:16:26 | x : T | -| Splitting.cs:16:26:16:26 | x : Object | Splitting.cs:16:32:16:32 | access to parameter x | -| Splitting.cs:16:26:16:26 | x : Object | Splitting.cs:16:32:16:32 | access to parameter x : T | -| Splitting.cs:16:26:16:26 | x : String | Splitting.cs:16:32:16:32 | access to parameter x | -| Splitting.cs:16:26:16:26 | x : String | Splitting.cs:16:32:16:32 | access to parameter x : String | -| Splitting.cs:16:26:16:26 | x : T | Splitting.cs:16:32:16:32 | access to parameter x | -| Splitting.cs:16:26:16:26 | x : T | Splitting.cs:16:32:16:32 | access to parameter x : T | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : T | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:20:22:20:30 | call to method Return | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:20:22:20:30 | call to method Return : T | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:21:21:21:33 | call to method Return | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:21:21:21:33 | call to method Return : T | -| Splitting.cs:18:24:18:24 | s : Object | Splitting.cs:18:24:18:24 | s | -| Splitting.cs:18:24:18:24 | s : Object | Splitting.cs:18:24:18:24 | s : String | -| Splitting.cs:18:24:18:24 | s : Object | Splitting.cs:20:29:20:29 | access to parameter s | -| Splitting.cs:18:24:18:24 | s : Object | Splitting.cs:20:29:20:29 | access to parameter s : String | -| Splitting.cs:18:24:18:24 | s : String | Splitting.cs:20:29:20:29 | access to parameter s | -| Splitting.cs:18:24:18:24 | s : String | Splitting.cs:20:29:20:29 | access to parameter s | -| Splitting.cs:18:24:18:24 | s : String | Splitting.cs:20:29:20:29 | access to parameter s : String | -| Splitting.cs:18:24:18:24 | s : String | Splitting.cs:20:29:20:29 | access to parameter s : String | -| Splitting.cs:20:22:20:30 | call to method Return : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:20:22:20:30 | call to method Return : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : String | -| Splitting.cs:20:22:20:30 | call to method Return : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:20:22:20:30 | call to method Return : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | -| Splitting.cs:20:22:20:30 | call to method Return : T | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:20:22:20:30 | call to method Return : T | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : T | -| Splitting.cs:20:22:20:30 | call to method Return : T | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:20:22:20:30 | call to method Return : T | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:16:26:16:26 | x : String | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:16:26:16:26 | x : String | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:20:22:20:30 | call to method Return | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:20:22:20:30 | call to method Return | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:20:22:20:30 | call to method Return : String | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:20:22:20:30 | call to method Return : String | -| Splitting.cs:21:9:21:11 | value : Object | Splitting.cs:21:9:21:11 | value | -| Splitting.cs:21:9:21:11 | value : Object | Splitting.cs:21:9:21:11 | value : String | -| Splitting.cs:21:9:21:11 | value : Object | Splitting.cs:21:28:21:32 | access to parameter value | -| Splitting.cs:21:9:21:11 | value : Object | Splitting.cs:21:28:21:32 | access to parameter value : String | -| Splitting.cs:21:9:21:11 | value : String | Splitting.cs:21:28:21:32 | access to parameter value | -| Splitting.cs:21:9:21:11 | value : String | Splitting.cs:21:28:21:32 | access to parameter value | -| Splitting.cs:21:9:21:11 | value : String | Splitting.cs:21:28:21:32 | access to parameter value : String | -| Splitting.cs:21:9:21:11 | value : String | Splitting.cs:21:28:21:32 | access to parameter value : String | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:16:26:16:26 | x : String | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:16:26:16:26 | x : String | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:21:21:21:33 | call to method Return | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:21:21:21:33 | call to method Return | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:21:21:21:33 | call to method Return : String | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:21:21:21:33 | call to method Return : String | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:21:29:24 | [b (line 24): false] this access | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:21:29:24 | [b (line 24): true] this access | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:24:18:24:18 | b : Boolean | Splitting.cs:26:13:26:13 | access to parameter b | -| Splitting.cs:24:18:24:18 | b : Boolean | Splitting.cs:26:13:26:13 | access to parameter b : Boolean | -| Splitting.cs:24:18:24:18 | b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): false] access to parameter b | -| Splitting.cs:24:18:24:18 | b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): false] access to parameter b : Boolean | -| Splitting.cs:24:18:24:18 | b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): true] access to parameter b | -| Splitting.cs:24:18:24:18 | b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): true] access to parameter b : Boolean | -| Splitting.cs:24:18:24:18 | b : Object | Splitting.cs:24:18:24:18 | b | -| Splitting.cs:24:18:24:18 | b : Object | Splitting.cs:24:18:24:18 | b : Boolean | -| Splitting.cs:24:18:24:18 | b : Object | Splitting.cs:26:13:26:13 | access to parameter b | -| Splitting.cs:24:18:24:18 | b : Object | Splitting.cs:26:13:26:13 | access to parameter b : Boolean | -| Splitting.cs:24:18:24:18 | b : Object | Splitting.cs:33:13:33:13 | [b (line 24): false] access to parameter b | -| Splitting.cs:24:18:24:18 | b : Object | Splitting.cs:33:13:33:13 | [b (line 24): false] access to parameter b : Boolean | -| Splitting.cs:24:18:24:18 | b : Object | Splitting.cs:33:13:33:13 | [b (line 24): true] access to parameter b | -| Splitting.cs:24:18:24:18 | b : Object | Splitting.cs:33:13:33:13 | [b (line 24): true] access to parameter b : Boolean | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:24:28:24:34 | tainted | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:24:28:24:34 | tainted : String | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:27:17:27:31 | [b (line 24): true] ... == ... | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:27:17:27:31 | [b (line 24): true] ... == ... : Boolean | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:27:17:27:31 | [b (line 24): true] ... == ... | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:27:17:27:31 | [b (line 24): true] ... == ... : Boolean | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:26:13:26:13 | access to parameter b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): false] access to parameter b | -| Splitting.cs:26:13:26:13 | access to parameter b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): false] access to parameter b : Boolean | -| Splitting.cs:26:13:26:13 | access to parameter b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): true] access to parameter b | -| Splitting.cs:26:13:26:13 | access to parameter b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): true] access to parameter b : Boolean | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:27:17:27:31 | [b (line 24): true] ... == ... | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:27:17:27:31 | [b (line 24): true] ... == ... : Boolean | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:21:9:21:11 | this | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:21:9:21:11 | this : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:21:9:21:11 | this | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:21:9:21:11 | this : Splitting | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:21:9:21:11 | this | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:21:9:21:11 | this : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:21:9:21:11 | this | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:21:9:21:11 | this : Splitting | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:21:9:21:11 | value | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:21:9:21:11 | value : String | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:21:9:21:11 | value | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:21:9:21:11 | value : String | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : String | -| Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : T | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : T | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : T | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : String | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : String | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : String | Splitting.cs:34:19:34:19 | access to local variable x : String | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : T | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : T | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : T | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : T | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : T | Splitting.cs:34:19:34:19 | access to local variable x : T | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | Splitting.cs:20:9:20:11 | this | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | Splitting.cs:20:9:20:11 | this : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:20:9:20:11 | this | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:20:9:20:11 | this : Splitting | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | Splitting.cs:20:9:20:11 | this | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | Splitting.cs:20:9:20:11 | this : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:20:9:20:11 | this | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:20:9:20:11 | this : Splitting | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : String | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : String | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : String | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : String | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : T | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : T | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : T | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : T | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : T | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : T | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : String | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : String | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:34:19:34:19 | access to local variable x : String | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : T | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : T | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | Splitting.cs:34:19:34:19 | access to local variable x : T | -| Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:18:24:18:24 | s | -| Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:18:24:18:24 | s : String | -| Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : String | -| Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:18:24:18:24 | s | -| Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:18:24:18:24 | s : String | -| Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | -| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : String | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : String | Splitting.cs:34:19:34:19 | access to local variable x : String | -| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : T | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : T | Splitting.cs:34:19:34:19 | access to local variable x : T | -| This.cs:9:20:9:20 | this : Sub | This.cs:11:13:11:16 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:11:13:11:16 | this access : Sub | -| This.cs:9:20:9:20 | this : Sub | This.cs:12:9:12:12 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:12:9:12:12 | this access : Sub | -| This.cs:9:20:9:20 | this : Sub | This.cs:12:16:12:19 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:12:16:12:19 | this access : Sub | -| This.cs:9:20:9:20 | this : Sub | This.cs:13:9:13:15 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:13:9:13:15 | this access : Sub | -| This.cs:9:20:9:20 | this : Sub | This.cs:13:11:13:14 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:13:11:13:14 | this access : Sub | -| This.cs:9:20:9:20 | this : Sub | This.cs:15:9:15:12 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:15:9:15:12 | this access : Sub | -| This.cs:9:20:9:20 | this : Sub | This.cs:16:9:16:16 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:9:20:9:20 | this : This | This.cs:11:13:11:16 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:11:13:11:16 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:11:13:11:16 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:11:13:11:16 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:12:9:12:12 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:12:9:12:12 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:12:9:12:12 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:12:9:12:12 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:12:16:12:19 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:12:16:12:19 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:12:16:12:19 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:12:16:12:19 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:13:9:13:15 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:13:9:13:15 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:13:9:13:15 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:13:9:13:15 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:13:11:13:14 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:13:11:13:14 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:13:11:13:14 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:13:11:13:14 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:15:9:15:12 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:15:9:15:12 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:15:9:15:12 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:15:9:15:12 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:16:9:16:16 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:16:9:16:16 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:16:9:16:16 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:16:9:16:16 | this access : This | -| This.cs:9:27:9:31 | other : Object | This.cs:9:27:9:31 | other | -| This.cs:9:27:9:31 | other : Object | This.cs:9:27:9:31 | other : This | -| This.cs:9:27:9:31 | other : Object | This.cs:14:13:14:17 | access to parameter other | -| This.cs:9:27:9:31 | other : Object | This.cs:14:13:14:17 | access to parameter other : This | -| This.cs:9:27:9:31 | other : Object | This.cs:15:16:15:20 | access to parameter other | -| This.cs:9:27:9:31 | other : Object | This.cs:15:16:15:20 | access to parameter other : This | -| This.cs:9:27:9:31 | other : Object | This.cs:16:11:16:15 | access to parameter other | -| This.cs:9:27:9:31 | other : Object | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:9:27:9:31 | other : Sub | This.cs:14:13:14:17 | access to parameter other | -| This.cs:9:27:9:31 | other : Sub | This.cs:14:13:14:17 | access to parameter other : Sub | -| This.cs:9:27:9:31 | other : Sub | This.cs:15:16:15:20 | access to parameter other | -| This.cs:9:27:9:31 | other : Sub | This.cs:15:16:15:20 | access to parameter other : Sub | -| This.cs:9:27:9:31 | other : Sub | This.cs:16:11:16:15 | access to parameter other | -| This.cs:9:27:9:31 | other : Sub | This.cs:16:11:16:15 | access to parameter other : Sub | -| This.cs:9:27:9:31 | other : This | This.cs:14:13:14:17 | access to parameter other | -| This.cs:9:27:9:31 | other : This | This.cs:14:13:14:17 | access to parameter other | -| This.cs:9:27:9:31 | other : This | This.cs:14:13:14:17 | access to parameter other : This | -| This.cs:9:27:9:31 | other : This | This.cs:14:13:14:17 | access to parameter other : This | -| This.cs:9:27:9:31 | other : This | This.cs:15:16:15:20 | access to parameter other | -| This.cs:9:27:9:31 | other : This | This.cs:15:16:15:20 | access to parameter other | -| This.cs:9:27:9:31 | other : This | This.cs:15:16:15:20 | access to parameter other : This | -| This.cs:9:27:9:31 | other : This | This.cs:15:16:15:20 | access to parameter other : This | -| This.cs:9:27:9:31 | other : This | This.cs:16:11:16:15 | access to parameter other | -| This.cs:9:27:9:31 | other : This | This.cs:16:11:16:15 | access to parameter other | -| This.cs:9:27:9:31 | other : This | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:9:27:9:31 | other : This | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:11:13:11:16 | this access : Sub | This.cs:12:9:12:12 | this access | -| This.cs:11:13:11:16 | this access : Sub | This.cs:12:9:12:12 | this access : Sub | -| This.cs:11:13:11:16 | this access : Sub | This.cs:12:16:12:19 | this access | -| This.cs:11:13:11:16 | this access : Sub | This.cs:12:16:12:19 | this access : Sub | -| This.cs:11:13:11:16 | this access : Sub | This.cs:13:9:13:15 | this access | -| This.cs:11:13:11:16 | this access : Sub | This.cs:13:9:13:15 | this access : Sub | -| This.cs:11:13:11:16 | this access : Sub | This.cs:13:11:13:14 | this access | -| This.cs:11:13:11:16 | this access : Sub | This.cs:13:11:13:14 | this access : Sub | -| This.cs:11:13:11:16 | this access : Sub | This.cs:15:9:15:12 | this access | -| This.cs:11:13:11:16 | this access : Sub | This.cs:15:9:15:12 | this access : Sub | -| This.cs:11:13:11:16 | this access : Sub | This.cs:16:9:16:16 | this access | -| This.cs:11:13:11:16 | this access : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:11:13:11:16 | this access : This | This.cs:12:9:12:12 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:12:9:12:12 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:12:9:12:12 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:12:9:12:12 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:12:16:12:19 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:12:16:12:19 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:12:16:12:19 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:12:16:12:19 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:13:9:13:15 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:13:9:13:15 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:13:9:13:15 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:13:9:13:15 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:12:9:12:12 | this access : Sub | This.cs:9:20:9:20 | this | -| This.cs:12:9:12:12 | this access : Sub | This.cs:9:20:9:20 | this : Sub | -| This.cs:12:9:12:12 | this access : Sub | This.cs:12:16:12:19 | this access | -| This.cs:12:9:12:12 | this access : Sub | This.cs:12:16:12:19 | this access : Sub | -| This.cs:12:9:12:12 | this access : Sub | This.cs:13:9:13:15 | this access | -| This.cs:12:9:12:12 | this access : Sub | This.cs:13:9:13:15 | this access : Sub | -| This.cs:12:9:12:12 | this access : Sub | This.cs:13:11:13:14 | this access | -| This.cs:12:9:12:12 | this access : Sub | This.cs:13:11:13:14 | this access : Sub | -| This.cs:12:9:12:12 | this access : Sub | This.cs:15:9:15:12 | this access | -| This.cs:12:9:12:12 | this access : Sub | This.cs:15:9:15:12 | this access : Sub | -| This.cs:12:9:12:12 | this access : Sub | This.cs:16:9:16:16 | this access | -| This.cs:12:9:12:12 | this access : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:12:9:12:12 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:12:9:12:12 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:12:9:12:12 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:12:9:12:12 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:12:9:12:12 | this access : This | This.cs:12:16:12:19 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:12:16:12:19 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:12:16:12:19 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:12:16:12:19 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:13:9:13:15 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:13:9:13:15 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:13:9:13:15 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:13:9:13:15 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:12:16:12:19 | this access : Sub | This.cs:9:27:9:31 | other | -| This.cs:12:16:12:19 | this access : Sub | This.cs:9:27:9:31 | other : Sub | -| This.cs:12:16:12:19 | this access : Sub | This.cs:13:9:13:15 | this access | -| This.cs:12:16:12:19 | this access : Sub | This.cs:13:9:13:15 | this access : Sub | -| This.cs:12:16:12:19 | this access : Sub | This.cs:13:11:13:14 | this access | -| This.cs:12:16:12:19 | this access : Sub | This.cs:13:11:13:14 | this access : Sub | -| This.cs:12:16:12:19 | this access : Sub | This.cs:15:9:15:12 | this access | -| This.cs:12:16:12:19 | this access : Sub | This.cs:15:9:15:12 | this access : Sub | -| This.cs:12:16:12:19 | this access : Sub | This.cs:16:9:16:16 | this access | -| This.cs:12:16:12:19 | this access : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:12:16:12:19 | this access : This | This.cs:9:27:9:31 | other | -| This.cs:12:16:12:19 | this access : This | This.cs:9:27:9:31 | other | -| This.cs:12:16:12:19 | this access : This | This.cs:9:27:9:31 | other : This | -| This.cs:12:16:12:19 | this access : This | This.cs:9:27:9:31 | other : This | -| This.cs:12:16:12:19 | this access : This | This.cs:13:9:13:15 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:13:9:13:15 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:13:9:13:15 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:13:9:13:15 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:13:9:13:15 | this access : Sub | This.cs:9:20:9:20 | this | -| This.cs:13:9:13:15 | this access : Sub | This.cs:9:20:9:20 | this : Sub | -| This.cs:13:9:13:15 | this access : Sub | This.cs:13:11:13:14 | this access | -| This.cs:13:9:13:15 | this access : Sub | This.cs:13:11:13:14 | this access : Sub | -| This.cs:13:9:13:15 | this access : Sub | This.cs:15:9:15:12 | this access | -| This.cs:13:9:13:15 | this access : Sub | This.cs:15:9:15:12 | this access : Sub | -| This.cs:13:9:13:15 | this access : Sub | This.cs:16:9:16:16 | this access | -| This.cs:13:9:13:15 | this access : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:13:9:13:15 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:13:9:13:15 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:13:9:13:15 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:13:9:13:15 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:13:9:13:15 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:13:9:13:15 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:13:9:13:15 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:13:9:13:15 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:13:9:13:15 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:13:9:13:15 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:13:9:13:15 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:13:9:13:15 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:13:9:13:15 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:13:9:13:15 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:13:9:13:15 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:13:9:13:15 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:13:11:13:14 | this access : Sub | This.cs:9:27:9:31 | other | -| This.cs:13:11:13:14 | this access : Sub | This.cs:9:27:9:31 | other : Sub | -| This.cs:13:11:13:14 | this access : Sub | This.cs:15:9:15:12 | this access | -| This.cs:13:11:13:14 | this access : Sub | This.cs:15:9:15:12 | this access : Sub | -| This.cs:13:11:13:14 | this access : Sub | This.cs:16:9:16:16 | this access | -| This.cs:13:11:13:14 | this access : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:13:11:13:14 | this access : This | This.cs:9:27:9:31 | other | -| This.cs:13:11:13:14 | this access : This | This.cs:9:27:9:31 | other | -| This.cs:13:11:13:14 | this access : This | This.cs:9:27:9:31 | other : This | -| This.cs:13:11:13:14 | this access : This | This.cs:9:27:9:31 | other : This | -| This.cs:13:11:13:14 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:13:11:13:14 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:13:11:13:14 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:13:11:13:14 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:13:11:13:14 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:13:11:13:14 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:13:11:13:14 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:13:11:13:14 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:14:13:14:17 | access to parameter other : Sub | This.cs:15:16:15:20 | access to parameter other | -| This.cs:14:13:14:17 | access to parameter other : Sub | This.cs:15:16:15:20 | access to parameter other : Sub | -| This.cs:14:13:14:17 | access to parameter other : Sub | This.cs:16:11:16:15 | access to parameter other | -| This.cs:14:13:14:17 | access to parameter other : Sub | This.cs:16:11:16:15 | access to parameter other : Sub | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:15:16:15:20 | access to parameter other | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:15:16:15:20 | access to parameter other | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:15:16:15:20 | access to parameter other : This | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:15:16:15:20 | access to parameter other : This | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:15:9:15:12 | this access : Sub | This.cs:9:20:9:20 | this | -| This.cs:15:9:15:12 | this access : Sub | This.cs:9:20:9:20 | this : Sub | -| This.cs:15:9:15:12 | this access : Sub | This.cs:16:9:16:16 | this access | -| This.cs:15:9:15:12 | this access : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:15:9:15:12 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:15:9:15:12 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:15:9:15:12 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:15:9:15:12 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:15:9:15:12 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:15:9:15:12 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:15:9:15:12 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:15:9:15:12 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:15:16:15:20 | access to parameter other : Sub | This.cs:9:27:9:31 | other | -| This.cs:15:16:15:20 | access to parameter other : Sub | This.cs:9:27:9:31 | other : Sub | -| This.cs:15:16:15:20 | access to parameter other : Sub | This.cs:16:11:16:15 | access to parameter other | -| This.cs:15:16:15:20 | access to parameter other : Sub | This.cs:16:11:16:15 | access to parameter other : Sub | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:9:27:9:31 | other | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:9:27:9:31 | other | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:9:27:9:31 | other : This | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:9:27:9:31 | other : This | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:16:9:16:16 | this access : Sub | This.cs:9:20:9:20 | this | -| This.cs:16:9:16:16 | this access : Sub | This.cs:9:20:9:20 | this : Sub | -| This.cs:16:9:16:16 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:16:9:16:16 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:16:9:16:16 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:16:9:16:16 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:16:11:16:15 | access to parameter other : Sub | This.cs:9:27:9:31 | other | -| This.cs:16:11:16:15 | access to parameter other : Sub | This.cs:9:27:9:31 | other : Sub | -| This.cs:16:11:16:15 | access to parameter other : This | This.cs:9:27:9:31 | other | -| This.cs:16:11:16:15 | access to parameter other : This | This.cs:9:27:9:31 | other | -| This.cs:16:11:16:15 | access to parameter other : This | This.cs:9:27:9:31 | other : This | -| This.cs:16:11:16:15 | access to parameter other : This | This.cs:9:27:9:31 | other : This | -| This.cs:17:9:17:18 | malloc : This | This.cs:7:5:7:8 | this | -| This.cs:17:9:17:18 | malloc : This | This.cs:7:5:7:8 | this : This | -| This.cs:24:14:24:15 | this : Sub | This.cs:26:13:26:16 | this access | -| This.cs:24:14:24:15 | this : Sub | This.cs:26:13:26:16 | this access : Sub | -| This.cs:24:14:24:15 | this : Sub | This.cs:26:20:26:23 | this access | -| This.cs:24:14:24:15 | this : Sub | This.cs:26:20:26:23 | this access : Sub | -| This.cs:24:14:24:15 | this : Sub | This.cs:27:13:27:16 | base access | -| This.cs:24:14:24:15 | this : Sub | This.cs:27:13:27:16 | base access : Sub | -| This.cs:24:14:24:15 | this : Sub | This.cs:27:20:27:23 | this access | -| This.cs:24:14:24:15 | this : Sub | This.cs:27:20:27:23 | this access : Sub | -| This.cs:26:13:26:16 | this access : Sub | This.cs:9:20:9:20 | this | -| This.cs:26:13:26:16 | this access : Sub | This.cs:9:20:9:20 | this : Sub | -| This.cs:26:13:26:16 | this access : Sub | This.cs:26:20:26:23 | this access | -| This.cs:26:13:26:16 | this access : Sub | This.cs:26:20:26:23 | this access : Sub | -| This.cs:26:13:26:16 | this access : Sub | This.cs:27:13:27:16 | base access | -| This.cs:26:13:26:16 | this access : Sub | This.cs:27:13:27:16 | base access : Sub | -| This.cs:26:13:26:16 | this access : Sub | This.cs:27:20:27:23 | this access | -| This.cs:26:13:26:16 | this access : Sub | This.cs:27:20:27:23 | this access : Sub | -| This.cs:26:20:26:23 | this access : Sub | This.cs:9:27:9:31 | other | -| This.cs:26:20:26:23 | this access : Sub | This.cs:9:27:9:31 | other : Sub | -| This.cs:26:20:26:23 | this access : Sub | This.cs:27:13:27:16 | base access | -| This.cs:26:20:26:23 | this access : Sub | This.cs:27:13:27:16 | base access : Sub | -| This.cs:26:20:26:23 | this access : Sub | This.cs:27:20:27:23 | this access | -| This.cs:26:20:26:23 | this access : Sub | This.cs:27:20:27:23 | this access : Sub | -| This.cs:27:13:27:16 | base access : Sub | This.cs:9:20:9:20 | this | -| This.cs:27:13:27:16 | base access : Sub | This.cs:9:20:9:20 | this : Sub | -| This.cs:27:13:27:16 | base access : Sub | This.cs:27:20:27:23 | this access | -| This.cs:27:13:27:16 | base access : Sub | This.cs:27:20:27:23 | this access : Sub | -| This.cs:27:13:27:16 | base access : This | This.cs:9:20:9:20 | this | -| This.cs:27:13:27:16 | base access : This | This.cs:9:20:9:20 | this : This | -| This.cs:27:13:27:16 | base access : This | This.cs:27:20:27:23 | this access | -| This.cs:27:13:27:16 | base access : This | This.cs:27:20:27:23 | this access : This | -| This.cs:27:20:27:23 | this access : Sub | This.cs:9:27:9:31 | other | -| This.cs:27:20:27:23 | this access : Sub | This.cs:9:27:9:31 | other : Sub | -| This.cs:27:20:27:23 | this access : This | This.cs:9:27:9:31 | other | -| This.cs:27:20:27:23 | this access : This | This.cs:9:27:9:31 | other : This | -| This.cs:28:13:28:21 | malloc : Sub | This.cs:22:9:22:11 | this | -| This.cs:28:13:28:21 | malloc : Sub | This.cs:22:9:22:11 | this : Sub | diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingEdges.ql b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingEdges.ql deleted file mode 100644 index 163130bea8f..00000000000 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingEdges.ql +++ /dev/null @@ -1,17 +0,0 @@ -import csharp -import DataFlow -import semmle.code.csharp.dataflow.internal.DataFlowPrivate - -class ConfigAny extends TaintTracking::Configuration { - ConfigAny() { this = "ConfigAny" } - - override predicate isSource(Node source) { - source instanceof PostUpdateNode implies source.asExpr() instanceof ObjectCreation - } - - override predicate isSink(Node sink) { - sink instanceof PostUpdateNode implies sink.asExpr() instanceof ObjectCreation - } -} - -query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b } diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected index c612897d3ee..7495630f875 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected @@ -75,7 +75,7 @@ edges | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | +| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | @@ -84,7 +84,7 @@ edges | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : String | +| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | | GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | @@ -100,31 +100,31 @@ edges | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:359:41:359:41 | x : String | +| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:361:41:361:41 | x : String | | GlobalDataFlow.cs:53:15:53:15 | x : String | GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | +| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:359:41:359:41 | x : String | +| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:361:41:361:41 | x : String | | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:373:52:373:52 | x : String | +| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:375:52:375:52 | x : String | | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:373:52:373:52 | x : String | +| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:375:52:375:52 | x : String | | GlobalDataFlow.cs:56:37:56:37 | x : String | GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | +| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:373:52:373:52 | x : String | +| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:375:52:375:52 | x : String | | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:404:9:404:11 | value : String | +| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:406:9:406:11 | value : String | | GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | | GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | @@ -140,27 +140,27 @@ edges | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | +| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:90:75:90:88 | call to method First : String | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | -| GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | -| GlobalDataFlow.cs:90:75:90:88 | call to method First : String | GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | +| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : T | +| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:294:31:294:40 | sinkParam8 : String[] | +| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | +| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | +| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | +| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : String | +| GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... : String | +| GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... : String | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | +| GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... : String | GlobalDataFlow.cs:86:70:86:113 | (...) ... : String[] | +| GlobalDataFlow.cs:86:70:86:113 | (...) ... : String[] | GlobalDataFlow.cs:86:117:86:127 | [output] (...) => ... : String | +| GlobalDataFlow.cs:86:117:86:127 | [output] (...) => ... : String | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | +| GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | GlobalDataFlow.cs:88:83:88:101 | [output] (...) => ... : String | +| GlobalDataFlow.cs:88:83:88:101 | [output] (...) => ... : String | GlobalDataFlow.cs:88:104:88:109 | [output] (...) => ... : String | +| GlobalDataFlow.cs:88:104:88:109 | [output] (...) => ... : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | +| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : String | GlobalDataFlow.cs:90:83:90:101 | [output] (...) => ... : String | +| GlobalDataFlow.cs:90:83:90:101 | [output] (...) => ... : String | GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | +| GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | +| GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | +| GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | | GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | | GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | GlobalDataFlow.cs:135:21:135:34 | delegate call : String | @@ -175,56 +175,56 @@ edges | GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:209:71:209:71 | x : IQueryable | GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 : String | -| GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 : String | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:209:71:209:71 | x : IQueryable | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : String | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 | -| GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : String | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : String | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:323:9:323:26 | SSA def(x) : String | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | -| GlobalDataFlow.cs:323:13:323:26 | "taint source" : String | GlobalDataFlow.cs:323:9:323:26 | SSA def(x) : String | -| GlobalDataFlow.cs:328:9:328:26 | SSA def(x) : String | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | -| GlobalDataFlow.cs:328:13:328:26 | "taint source" : String | GlobalDataFlow.cs:328:9:328:26 | SSA def(x) : String | -| GlobalDataFlow.cs:334:22:334:35 | "taint source" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | -| GlobalDataFlow.cs:334:22:334:35 | "taint source" : String | GlobalDataFlow.cs:334:22:334:35 | "taint source" : IEnumerable | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:53:15:53:15 | x : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:415:22:415:35 | "taint source" : String | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | +| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:212:22:212:28 | access to local variable tainted : IQueryable | +| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:214:22:214:28 | access to local variable tainted : IQueryable | +| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:216:22:216:28 | access to local variable tainted : IQueryable | +| GlobalDataFlow.cs:210:35:210:45 | sinkParam10 : IQueryable | GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | +| GlobalDataFlow.cs:211:71:211:71 | x : IQueryable | GlobalDataFlow.cs:211:89:211:89 | access to parameter x : String | +| GlobalDataFlow.cs:211:89:211:89 | access to parameter x : String | GlobalDataFlow.cs:300:32:300:41 | sinkParam9 : String | +| GlobalDataFlow.cs:212:22:212:28 | access to local variable tainted : IQueryable | GlobalDataFlow.cs:210:35:210:45 | sinkParam10 : IQueryable | +| GlobalDataFlow.cs:212:22:212:28 | access to local variable tainted : IQueryable | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f1 : String | +| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f1 : String | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | +| GlobalDataFlow.cs:214:22:214:28 | access to local variable tainted : IQueryable | GlobalDataFlow.cs:211:71:211:71 | x : IQueryable | +| GlobalDataFlow.cs:214:22:214:28 | access to local variable tainted : IQueryable | GlobalDataFlow.cs:214:37:214:38 | [output] access to local variable f2 : String | +| GlobalDataFlow.cs:214:37:214:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | +| GlobalDataFlow.cs:216:22:216:28 | access to local variable tainted : IQueryable | GlobalDataFlow.cs:216:37:216:48 | [output] delegate creation of type Func : T | +| GlobalDataFlow.cs:216:22:216:28 | access to local variable tainted : IQueryable | GlobalDataFlow.cs:306:32:306:42 | sinkParam11 : IQueryable | +| GlobalDataFlow.cs:216:37:216:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | +| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | +| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | +| GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:294:31:294:40 | sinkParam8 : String[] | GlobalDataFlow.cs:296:15:296:24 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:300:32:300:41 | sinkParam9 : String | GlobalDataFlow.cs:302:15:302:24 | access to parameter sinkParam9 | +| GlobalDataFlow.cs:306:32:306:42 | sinkParam11 : IQueryable | GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | +| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | +| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | +| GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | +| GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | +| GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | +| GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | +| GlobalDataFlow.cs:336:22:336:35 | "taint source" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | +| GlobalDataFlow.cs:336:22:336:35 | "taint source" : String | GlobalDataFlow.cs:336:22:336:35 | "taint source" : IEnumerable | +| GlobalDataFlow.cs:361:41:361:41 | x : String | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | +| GlobalDataFlow.cs:361:41:361:41 | x : String | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | +| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | GlobalDataFlow.cs:53:15:53:15 | x : String | +| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | +| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | +| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | +| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | +| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x : String | +| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | +| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | +| GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | +| GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | +| GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | +| GlobalDataFlow.cs:406:9:406:11 | value : String | GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | +| GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | @@ -333,22 +333,22 @@ nodes | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | semmle.label | call to method SelectEven : IEnumerable | | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | semmle.label | (...) ... : String[] | | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | semmle.label | access to local variable sink13 | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | semmle.label | (...) ... : String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | semmle.label | [output] delegate creation of type Func : T | +| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | +| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : T | semmle.label | [output] delegate creation of type Func : T | | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | semmle.label | access to local variable sink14 | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | semmle.label | (...) ... : String[] | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | +| GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | +| GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | semmle.label | access to local variable sink15 | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | semmle.label | (...) ... : String[] | -| GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | +| GlobalDataFlow.cs:86:70:86:113 | (...) ... : String[] | semmle.label | (...) ... : String[] | +| GlobalDataFlow.cs:86:117:86:127 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | semmle.label | access to local variable sink16 | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | semmle.label | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | +| GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | +| GlobalDataFlow.cs:88:83:88:101 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | +| GlobalDataFlow.cs:88:104:88:109 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | semmle.label | access to local variable sink17 | -| GlobalDataFlow.cs:90:75:90:88 | call to method First : String | semmle.label | call to method First : String | -| GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | +| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : String | semmle.label | access to local variable sink14 : String | +| GlobalDataFlow.cs:90:83:90:101 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | +| GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | semmle.label | access to local variable sink18 | | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | semmle.label | access to local variable sink21 | | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | semmle.label | access to local variable sink22 | @@ -375,64 +375,64 @@ nodes | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | semmle.label | access to local variable sink10 | | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | semmle.label | access to property OutProperty : String | | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | semmle.label | access to local variable sink19 | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | semmle.label | tainted : IQueryable | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | semmle.label | sinkParam10 : IQueryable | -| GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 | semmle.label | access to parameter sinkParam10 | -| GlobalDataFlow.cs:209:71:209:71 | x : IQueryable | semmle.label | x : IQueryable | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | semmle.label | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 : String | semmle.label | [output] access to local variable f1 : String | -| GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 | semmle.label | access to local variable sink24 | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | semmle.label | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : String | semmle.label | [output] access to local variable f2 : String | -| GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 | semmle.label | access to local variable sink25 | -| GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | semmle.label | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : T | semmle.label | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 | semmle.label | access to local variable sink26 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | semmle.label | sinkParam0 : String | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | semmle.label | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | semmle.label | access to parameter sinkParam0 | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : String | semmle.label | sinkParam1 : String | -| GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | semmle.label | access to parameter sinkParam1 | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : String | semmle.label | sinkParam3 : String | -| GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | semmle.label | access to parameter sinkParam3 | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | semmle.label | sinkParam4 : String | -| GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | semmle.label | access to parameter sinkParam4 | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | semmle.label | sinkParam5 : String | -| GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | semmle.label | access to parameter sinkParam5 | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | semmle.label | sinkParam6 : String | -| GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | semmle.label | access to parameter sinkParam6 | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | semmle.label | sinkParam7 : String | -| GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | semmle.label | access to parameter sinkParam7 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | semmle.label | sinkParam8 : String[] | -| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | semmle.label | access to parameter sinkParam8 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | semmle.label | sinkParam9 : String | -| GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 | semmle.label | access to parameter sinkParam9 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | semmle.label | sinkParam11 : IQueryable | -| GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 | semmle.label | access to parameter sinkParam11 | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:323:9:323:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | -| GlobalDataFlow.cs:323:13:323:26 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:328:9:328:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | -| GlobalDataFlow.cs:328:13:328:26 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:334:22:334:35 | "taint source" : IEnumerable | semmle.label | "taint source" : IEnumerable | -| GlobalDataFlow.cs:334:22:334:35 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:359:41:359:41 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:359:41:359:41 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | semmle.label | tainted : String | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | semmle.label | access to local variable sink11 | -| GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | semmle.label | access to local variable sink11 : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | semmle.label | value : String | -| GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | semmle.label | access to local variable sink20 | -| GlobalDataFlow.cs:415:22:415:35 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:210:35:210:45 | sinkParam10 : IQueryable | semmle.label | sinkParam10 : IQueryable | +| GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | semmle.label | access to parameter sinkParam10 | +| GlobalDataFlow.cs:211:71:211:71 | x : IQueryable | semmle.label | x : IQueryable | +| GlobalDataFlow.cs:211:89:211:89 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:212:22:212:28 | access to local variable tainted : IQueryable | semmle.label | access to local variable tainted : IQueryable | +| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f1 : String | semmle.label | [output] access to local variable f1 : String | +| GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | semmle.label | access to local variable sink24 | +| GlobalDataFlow.cs:214:22:214:28 | access to local variable tainted : IQueryable | semmle.label | access to local variable tainted : IQueryable | +| GlobalDataFlow.cs:214:37:214:38 | [output] access to local variable f2 : String | semmle.label | [output] access to local variable f2 : String | +| GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | semmle.label | access to local variable sink25 | +| GlobalDataFlow.cs:216:22:216:28 | access to local variable tainted : IQueryable | semmle.label | access to local variable tainted : IQueryable | +| GlobalDataFlow.cs:216:37:216:48 | [output] delegate creation of type Func : T | semmle.label | [output] delegate creation of type Func : T | +| GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | semmle.label | access to local variable sink26 | +| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | semmle.label | sinkParam0 : String | +| GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | semmle.label | access to parameter sinkParam0 : String | +| GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | semmle.label | access to parameter sinkParam0 | +| GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | semmle.label | sinkParam1 : String | +| GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | semmle.label | access to parameter sinkParam1 | +| GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | semmle.label | sinkParam3 : String | +| GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | semmle.label | access to parameter sinkParam3 | +| GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | semmle.label | sinkParam4 : String | +| GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | semmle.label | access to parameter sinkParam4 | +| GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | semmle.label | sinkParam5 : String | +| GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | semmle.label | access to parameter sinkParam5 | +| GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | semmle.label | sinkParam6 : String | +| GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | semmle.label | access to parameter sinkParam6 | +| GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | semmle.label | sinkParam7 : String | +| GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | semmle.label | access to parameter sinkParam7 | +| GlobalDataFlow.cs:294:31:294:40 | sinkParam8 : String[] | semmle.label | sinkParam8 : String[] | +| GlobalDataFlow.cs:296:15:296:24 | access to parameter sinkParam8 | semmle.label | access to parameter sinkParam8 | +| GlobalDataFlow.cs:300:32:300:41 | sinkParam9 : String | semmle.label | sinkParam9 : String | +| GlobalDataFlow.cs:302:15:302:24 | access to parameter sinkParam9 | semmle.label | access to parameter sinkParam9 | +| GlobalDataFlow.cs:306:32:306:42 | sinkParam11 : IQueryable | semmle.label | sinkParam11 : IQueryable | +| GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | semmle.label | access to parameter sinkParam11 | +| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | +| GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | +| GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:336:22:336:35 | "taint source" : IEnumerable | semmle.label | "taint source" : IEnumerable | +| GlobalDataFlow.cs:336:22:336:35 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:361:41:361:41 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:361:41:361:41 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:380:39:380:45 | tainted : String | semmle.label | tainted : String | +| GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | semmle.label | access to local variable sink11 | +| GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | semmle.label | access to local variable sink11 : String | +| GlobalDataFlow.cs:406:9:406:11 | value : String | semmle.label | value : String | +| GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | semmle.label | access to local variable sink20 | +| GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | semmle.label | "taint source" : String | | Splitting.cs:3:28:3:34 | tainted : String | semmle.label | tainted : String | | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | semmle.label | [b (line 3): false] call to method Return : String | | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | semmle.label | [b (line 3): true] call to method Return : String | @@ -485,30 +485,30 @@ nodes | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | access to local variable sink22 | | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | access to local variable sink4 | | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | access to local variable sink5 | -| GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | access to local variable sink6 | -| GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | GlobalDataFlow.cs:323:13:323:26 | "taint source" : String | GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | access to local variable sink7 | -| GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | GlobalDataFlow.cs:328:13:328:26 | "taint source" : String | GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | access to local variable sink8 | -| GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | GlobalDataFlow.cs:334:22:334:35 | "taint source" : String | GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | access to local variable sink12 | -| GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | access to local variable sink23 | +| GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | access to local variable sink6 | +| GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | access to local variable sink7 | +| GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | access to local variable sink8 | +| GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | GlobalDataFlow.cs:336:22:336:35 | "taint source" : String | GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | access to local variable sink12 | +| GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | access to local variable sink23 | | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | access to local variable sink9 | -| GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | access to local variable sink10 | -| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | GlobalDataFlow.cs:415:22:415:35 | "taint source" : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | access to local variable sink19 | -| GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 | GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 | GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 | access to local variable sink24 | -| GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 | GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 | access to local variable sink25 | -| GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 | GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 | access to local variable sink26 | -| GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 | GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 | GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | access to local variable sink11 | -| GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | access to local variable sink20 | +| GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | access to local variable sink10 | +| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | access to local variable sink19 | +| GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | access to parameter sinkParam10 | +| GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | access to local variable sink24 | +| GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | access to local variable sink25 | +| GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | access to local variable sink26 | +| GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:296:15:296:24 | access to parameter sinkParam8 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:296:15:296:24 | access to parameter sinkParam8 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:302:15:302:24 | access to parameter sinkParam9 | GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:302:15:302:24 | access to parameter sinkParam9 | access to parameter sinkParam9 | +| GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | access to parameter sinkParam11 | +| GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | access to local variable sink11 | +| GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | access to local variable sink20 | | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | [b (line 3): false] access to local variable x | | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | [b (line 3): true] access to local variable x | | Splitting.cs:11:19:11:19 | access to local variable x | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:11:19:11:19 | access to local variable x | access to local variable x | diff --git a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected index 6631539ed2d..ce4eba806a2 100644 --- a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected @@ -1139,6 +1139,8 @@ | System.Linq.Queryable.Aggregate(IQueryable, Expression>) | output from argument 1 -> return | false | | System.Linq.Queryable.All(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.Queryable.Any(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.AsQueryable(IEnumerable) | argument 0 -> return | false | +| System.Linq.Queryable.AsQueryable(IEnumerable) | argument 0 -> return | false | | System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected b/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected index 78c0204ed20..e9a03e58b0a 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected @@ -1,16 +1,12 @@ | LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | -| LocalDataFlow.cs:300:15:300:20 | access to local variable sink40 | -| LocalDataFlow.cs:302:15:302:20 | access to local variable sink41 | -| LocalDataFlow.cs:304:15:304:20 | access to local variable sink42 | -| LocalDataFlow.cs:306:15:306:20 | access to local variable sink43 | -| LocalDataFlow.cs:392:15:392:20 | access to local variable sink67 | -| LocalDataFlow.cs:394:15:394:20 | access to local variable sink68 | -| LocalDataFlow.cs:412:15:412:20 | access to local variable sink70 | -| LocalDataFlow.cs:420:19:420:24 | access to local variable sink71 | -| LocalDataFlow.cs:430:23:430:28 | access to local variable sink72 | -| LocalDataFlow.cs:445:15:445:20 | access to local variable sink73 | -| LocalDataFlow.cs:446:15:446:20 | access to local variable sink74 | -| LocalDataFlow.cs:472:15:472:21 | access to parameter tainted | +| LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | +| LocalDataFlow.cs:277:15:277:20 | access to local variable sink68 | +| LocalDataFlow.cs:295:15:295:20 | access to local variable sink70 | +| LocalDataFlow.cs:303:19:303:24 | access to local variable sink71 | +| LocalDataFlow.cs:313:23:313:28 | access to local variable sink72 | +| LocalDataFlow.cs:328:15:328:20 | access to local variable sink73 | +| LocalDataFlow.cs:329:15:329:20 | access to local variable sink74 | +| LocalDataFlow.cs:355:15:355:21 | access to parameter tainted | | SSA.cs:9:15:9:22 | access to local variable ssaSink0 | | SSA.cs:25:15:25:22 | access to local variable ssaSink1 | | SSA.cs:43:15:43:22 | access to local variable ssaSink2 | diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected index 658dc392eee..e3166a0df30 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -24,8 +24,7 @@ | Capture.cs:58:21:58:21 | 1 | Capture.cs:58:17:58:21 | SSA def(i) | | Capture.cs:61:17:61:17 | 1 | Capture.cs:61:13:61:17 | SSA def(i) | | Capture.cs:63:9:63:17 | SSA call def(i) | Capture.cs:64:13:64:13 | access to local variable i | -| LocalDataFlow.cs:49:23:49:23 | this | LocalDataFlow.cs:299:39:299:51 | this access | -| LocalDataFlow.cs:49:30:49:30 | b | LocalDataFlow.cs:96:21:96:21 | access to parameter b | +| LocalDataFlow.cs:49:30:49:30 | b | LocalDataFlow.cs:85:21:85:21 | access to parameter b | | LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | | LocalDataFlow.cs:52:21:52:34 | "taint source" | LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | | LocalDataFlow.cs:53:15:53:19 | [post] access to local variable sink0 | LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | @@ -38,567 +37,396 @@ | LocalDataFlow.cs:60:21:60:25 | "abc" | LocalDataFlow.cs:60:13:60:25 | SSA def(sink1) | | LocalDataFlow.cs:61:9:61:22 | ... + ... | LocalDataFlow.cs:61:9:61:22 | SSA def(sink1) | | LocalDataFlow.cs:61:9:61:22 | SSA def(sink1) | LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | -| LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | LocalDataFlow.cs:204:20:204:24 | access to local variable sink0 | -| LocalDataFlow.cs:62:15:62:19 | [post] access to local variable sink1 | LocalDataFlow.cs:70:23:70:27 | access to local variable sink1 | -| LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | LocalDataFlow.cs:70:23:70:27 | access to local variable sink1 | +| LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | LocalDataFlow.cs:169:20:169:24 | access to local variable sink0 | +| LocalDataFlow.cs:62:15:62:19 | [post] access to local variable sink1 | LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | +| LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | | LocalDataFlow.cs:65:9:65:25 | ... + ... | LocalDataFlow.cs:65:9:65:25 | SSA def(nonSink0) | | LocalDataFlow.cs:65:9:65:25 | SSA def(nonSink0) | LocalDataFlow.cs:66:15:66:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:66:15:66:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:75:24:75:31 | access to local variable nonSink0 | -| LocalDataFlow.cs:66:15:66:22 | access to local variable nonSink0 | LocalDataFlow.cs:75:24:75:31 | access to local variable nonSink0 | -| LocalDataFlow.cs:69:13:69:51 | SSA def(sink2) | LocalDataFlow.cs:70:9:70:13 | access to local variable sink2 | -| LocalDataFlow.cs:69:21:69:51 | object creation of type Dictionary | LocalDataFlow.cs:69:13:69:51 | SSA def(sink2) | -| LocalDataFlow.cs:70:9:70:13 | [post] access to local variable sink2 | LocalDataFlow.cs:71:15:71:19 | access to local variable sink2 | -| LocalDataFlow.cs:70:9:70:13 | access to local variable sink2 | LocalDataFlow.cs:71:15:71:19 | access to local variable sink2 | -| LocalDataFlow.cs:70:23:70:27 | access to local variable sink1 | LocalDataFlow.cs:76:18:76:22 | access to local variable sink1 | -| LocalDataFlow.cs:74:13:74:55 | SSA def(nonSink1) | LocalDataFlow.cs:75:9:75:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:74:24:74:55 | object creation of type Dictionary | LocalDataFlow.cs:74:13:74:55 | SSA def(nonSink1) | -| LocalDataFlow.cs:75:9:75:16 | [post] access to local variable nonSink1 | LocalDataFlow.cs:76:9:76:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:75:9:75:16 | access to local variable nonSink1 | LocalDataFlow.cs:76:9:76:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:75:24:75:31 | [post] access to local variable nonSink0 | LocalDataFlow.cs:84:20:84:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:75:24:75:31 | access to local variable nonSink0 | LocalDataFlow.cs:84:20:84:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:76:9:76:16 | [post] access to local variable nonSink1 | LocalDataFlow.cs:77:15:77:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:76:9:76:16 | access to local variable nonSink1 | LocalDataFlow.cs:77:15:77:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:76:18:76:22 | [post] access to local variable sink1 | LocalDataFlow.cs:80:21:80:25 | access to local variable sink1 | -| LocalDataFlow.cs:76:18:76:22 | access to local variable sink1 | LocalDataFlow.cs:80:21:80:25 | access to local variable sink1 | -| LocalDataFlow.cs:80:13:80:32 | SSA def(sink5) | LocalDataFlow.cs:81:15:81:19 | access to local variable sink5 | -| LocalDataFlow.cs:80:21:80:25 | access to local variable sink1 | LocalDataFlow.cs:204:33:204:37 | access to local variable sink1 | -| LocalDataFlow.cs:80:21:80:32 | ... + ... | LocalDataFlow.cs:80:13:80:32 | SSA def(sink5) | -| LocalDataFlow.cs:81:15:81:19 | [post] access to local variable sink5 | LocalDataFlow.cs:88:22:88:26 | access to local variable sink5 | -| LocalDataFlow.cs:81:15:81:19 | access to local variable sink5 | LocalDataFlow.cs:88:22:88:26 | access to local variable sink5 | -| LocalDataFlow.cs:84:9:84:36 | SSA def(nonSink0) | LocalDataFlow.cs:85:15:85:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:84:20:84:36 | ... + ... | LocalDataFlow.cs:84:9:84:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:85:15:85:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:92:21:92:28 | access to local variable nonSink0 | -| LocalDataFlow.cs:85:15:85:22 | access to local variable nonSink0 | LocalDataFlow.cs:92:21:92:28 | access to local variable nonSink0 | -| LocalDataFlow.cs:88:13:88:27 | SSA def(sink6) | LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | -| LocalDataFlow.cs:88:22:88:26 | access to local variable sink5 | LocalDataFlow.cs:88:13:88:27 | SSA def(sink6) | -| LocalDataFlow.cs:89:15:89:19 | [post] access to local variable sink6 | LocalDataFlow.cs:96:31:96:35 | [b (line 49): false] access to local variable sink6 | -| LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | LocalDataFlow.cs:96:31:96:35 | [b (line 49): false] access to local variable sink6 | -| LocalDataFlow.cs:92:9:92:29 | SSA def(nonSink0) | LocalDataFlow.cs:93:15:93:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:92:21:92:28 | access to local variable nonSink0 | LocalDataFlow.cs:92:9:92:29 | SSA def(nonSink0) | -| LocalDataFlow.cs:96:13:96:35 | [b (line 49): false] SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | [b (line 49): false] access to local variable sink7 | -| LocalDataFlow.cs:96:13:96:35 | [b (line 49): true] SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | [b (line 49): true] access to local variable sink7 | -| LocalDataFlow.cs:96:21:96:21 | access to parameter b | LocalDataFlow.cs:100:20:100:20 | [b (line 49): false] access to parameter b | -| LocalDataFlow.cs:96:21:96:21 | access to parameter b | LocalDataFlow.cs:100:20:100:20 | [b (line 49): true] access to parameter b | -| LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | LocalDataFlow.cs:96:13:96:35 | [b (line 49): false] SSA def(sink7) | -| LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | LocalDataFlow.cs:96:13:96:35 | [b (line 49): true] SSA def(sink7) | -| LocalDataFlow.cs:96:25:96:27 | [b (line 49): true] "a" | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | -| LocalDataFlow.cs:96:31:96:35 | [b (line 49): false] access to local variable sink6 | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | -| LocalDataFlow.cs:97:15:97:19 | [b (line 49): false] access to local variable sink7 | LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | -| LocalDataFlow.cs:97:15:97:19 | [b (line 49): true] access to local variable sink7 | LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | -| LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | LocalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | LocalDataFlow.cs:104:29:104:33 | access to local variable sink7 | -| LocalDataFlow.cs:100:20:100:36 | [b (line 49): false] ... ? ... : ... | LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:100:20:100:36 | [b (line 49): true] ... ? ... : ... | LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:100:24:100:28 | "abc" | LocalDataFlow.cs:100:20:100:36 | [b (line 49): true] ... ? ... : ... | -| LocalDataFlow.cs:100:32:100:36 | "def" | LocalDataFlow.cs:100:20:100:36 | [b (line 49): false] ... ? ... : ... | -| LocalDataFlow.cs:101:15:101:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:108:32:108:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | LocalDataFlow.cs:108:32:108:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:104:13:104:33 | SSA def(sink8) | LocalDataFlow.cs:105:15:105:19 | access to local variable sink8 | -| LocalDataFlow.cs:104:21:104:33 | (...) ... | LocalDataFlow.cs:104:13:104:33 | SSA def(sink8) | -| LocalDataFlow.cs:104:29:104:33 | access to local variable sink7 | LocalDataFlow.cs:104:21:104:33 | (...) ... | -| LocalDataFlow.cs:105:15:105:19 | [post] access to local variable sink8 | LocalDataFlow.cs:112:21:112:25 | access to local variable sink8 | -| LocalDataFlow.cs:105:15:105:19 | access to local variable sink8 | LocalDataFlow.cs:112:21:112:25 | access to local variable sink8 | -| LocalDataFlow.cs:108:13:108:39 | SSA def(nonSink3) | LocalDataFlow.cs:109:15:109:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:108:24:108:39 | (...) ... | LocalDataFlow.cs:108:13:108:39 | SSA def(nonSink3) | -| LocalDataFlow.cs:108:32:108:39 | access to local variable nonSink0 | LocalDataFlow.cs:108:24:108:39 | (...) ... | -| LocalDataFlow.cs:108:32:108:39 | access to local variable nonSink0 | LocalDataFlow.cs:116:20:116:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:112:13:112:35 | SSA def(sink9) | LocalDataFlow.cs:113:15:113:19 | access to local variable sink9 | -| LocalDataFlow.cs:112:21:112:25 | access to local variable sink8 | LocalDataFlow.cs:112:21:112:35 | ... as ... | -| LocalDataFlow.cs:112:21:112:25 | access to local variable sink8 | LocalDataFlow.cs:200:22:200:26 | access to local variable sink8 | -| LocalDataFlow.cs:112:21:112:35 | ... as ... | LocalDataFlow.cs:112:13:112:35 | SSA def(sink9) | -| LocalDataFlow.cs:113:15:113:19 | [post] access to local variable sink9 | LocalDataFlow.cs:120:37:120:41 | access to local variable sink9 | -| LocalDataFlow.cs:113:15:113:19 | access to local variable sink9 | LocalDataFlow.cs:120:37:120:41 | access to local variable sink9 | -| LocalDataFlow.cs:116:9:116:37 | SSA def(nonSink3) | LocalDataFlow.cs:117:15:117:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:116:20:116:27 | access to local variable nonSink0 | LocalDataFlow.cs:116:20:116:37 | ... as ... | -| LocalDataFlow.cs:116:20:116:27 | access to local variable nonSink0 | LocalDataFlow.cs:149:22:149:29 | access to local variable nonSink0 | -| LocalDataFlow.cs:116:20:116:37 | ... as ... | LocalDataFlow.cs:116:9:116:37 | SSA def(nonSink3) | -| LocalDataFlow.cs:120:13:120:43 | SSA def(sink10) | LocalDataFlow.cs:121:15:121:20 | access to local variable sink10 | -| LocalDataFlow.cs:120:22:120:43 | array creation of type Object[] | LocalDataFlow.cs:120:13:120:43 | SSA def(sink10) | -| LocalDataFlow.cs:120:37:120:41 | access to local variable sink9 | LocalDataFlow.cs:128:61:128:65 | access to local variable sink9 | -| LocalDataFlow.cs:121:15:121:20 | [post] access to local variable sink10 | LocalDataFlow.cs:218:22:218:27 | access to local variable sink10 | -| LocalDataFlow.cs:121:15:121:20 | access to local variable sink10 | LocalDataFlow.cs:218:22:218:27 | access to local variable sink10 | -| LocalDataFlow.cs:124:13:124:42 | SSA def(nonSink4) | LocalDataFlow.cs:125:15:125:22 | access to local variable nonSink4 | -| LocalDataFlow.cs:124:24:124:42 | array creation of type Object[] | LocalDataFlow.cs:124:13:124:42 | SSA def(nonSink4) | -| LocalDataFlow.cs:124:39:124:40 | 42 | LocalDataFlow.cs:124:39:124:40 | (...) ... | -| LocalDataFlow.cs:125:15:125:22 | [post] access to local variable nonSink4 | LocalDataFlow.cs:222:20:222:27 | access to local variable nonSink4 | -| LocalDataFlow.cs:125:15:125:22 | access to local variable nonSink4 | LocalDataFlow.cs:222:20:222:27 | access to local variable nonSink4 | -| LocalDataFlow.cs:128:13:128:69 | SSA def(sink11) | LocalDataFlow.cs:129:15:129:20 | access to local variable sink11 | -| LocalDataFlow.cs:128:22:128:69 | object creation of type Dictionary | LocalDataFlow.cs:128:13:128:69 | SSA def(sink11) | -| LocalDataFlow.cs:128:61:128:65 | [post] access to local variable sink9 | LocalDataFlow.cs:132:55:132:59 | access to local variable sink9 | -| LocalDataFlow.cs:128:61:128:65 | access to local variable sink9 | LocalDataFlow.cs:132:55:132:59 | access to local variable sink9 | -| LocalDataFlow.cs:129:15:129:20 | [post] access to local variable sink11 | LocalDataFlow.cs:136:22:136:27 | access to local variable sink11 | -| LocalDataFlow.cs:129:15:129:20 | access to local variable sink11 | LocalDataFlow.cs:136:22:136:27 | access to local variable sink11 | -| LocalDataFlow.cs:132:9:132:67 | SSA def(nonSink1) | LocalDataFlow.cs:133:15:133:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:132:20:132:67 | object creation of type Dictionary | LocalDataFlow.cs:132:9:132:67 | SSA def(nonSink1) | -| LocalDataFlow.cs:132:55:132:59 | [post] access to local variable sink9 | LocalDataFlow.cs:144:34:144:38 | access to local variable sink9 | -| LocalDataFlow.cs:132:55:132:59 | access to local variable sink9 | LocalDataFlow.cs:144:34:144:38 | access to local variable sink9 | -| LocalDataFlow.cs:133:15:133:22 | [post] access to local variable nonSink1 | LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink1 | -| LocalDataFlow.cs:133:15:133:22 | access to local variable nonSink1 | LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink1 | -| LocalDataFlow.cs:136:13:136:55 | SSA def(sink14) | LocalDataFlow.cs:137:15:137:20 | access to local variable sink14 | -| LocalDataFlow.cs:136:22:136:27 | [post] access to local variable sink11 | LocalDataFlow.cs:210:22:210:27 | access to local variable sink11 | -| LocalDataFlow.cs:136:22:136:27 | access to local variable sink11 | LocalDataFlow.cs:210:22:210:27 | access to local variable sink11 | -| LocalDataFlow.cs:136:22:136:55 | call to method First | LocalDataFlow.cs:136:13:136:55 | SSA def(sink14) | -| LocalDataFlow.cs:136:35:136:35 | x | LocalDataFlow.cs:136:40:136:40 | access to parameter x | -| LocalDataFlow.cs:136:40:136:40 | access to parameter x | LocalDataFlow.cs:136:40:136:46 | access to property Value | -| LocalDataFlow.cs:140:9:140:55 | SSA def(nonSink3) | LocalDataFlow.cs:206:33:206:40 | access to local variable nonSink3 | -| LocalDataFlow.cs:140:20:140:27 | [post] access to local variable nonSink1 | LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink1 | LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:140:20:140:55 | (...) ... | LocalDataFlow.cs:140:9:140:55 | SSA def(nonSink3) | -| LocalDataFlow.cs:140:20:140:55 | call to method First | LocalDataFlow.cs:140:20:140:55 | (...) ... | -| LocalDataFlow.cs:140:35:140:35 | x | LocalDataFlow.cs:140:40:140:40 | access to parameter x | -| LocalDataFlow.cs:140:40:140:40 | access to parameter x | LocalDataFlow.cs:140:40:140:46 | access to property Value | -| LocalDataFlow.cs:141:15:141:22 | [post] access to local variable nonSink1 | LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink1 | -| LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink1 | LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink1 | -| LocalDataFlow.cs:144:13:144:39 | SSA def(sink15) | LocalDataFlow.cs:145:15:145:20 | access to local variable sink15 | -| LocalDataFlow.cs:144:22:144:39 | call to method Parse | LocalDataFlow.cs:144:13:144:39 | SSA def(sink15) | -| LocalDataFlow.cs:144:34:144:38 | [post] access to local variable sink9 | LocalDataFlow.cs:147:37:147:41 | access to local variable sink9 | -| LocalDataFlow.cs:144:34:144:38 | access to local variable sink9 | LocalDataFlow.cs:147:37:147:41 | access to local variable sink9 | -| LocalDataFlow.cs:145:15:145:20 | access to local variable sink15 | LocalDataFlow.cs:196:22:196:27 | access to local variable sink15 | -| LocalDataFlow.cs:147:13:147:56 | SSA def(sink16) | LocalDataFlow.cs:148:15:148:20 | access to local variable sink16 | -| LocalDataFlow.cs:147:22:147:56 | call to method TryParse | LocalDataFlow.cs:147:13:147:56 | SSA def(sink16) | -| LocalDataFlow.cs:147:37:147:41 | [post] access to local variable sink9 | LocalDataFlow.cs:149:44:149:48 | access to local variable sink9 | -| LocalDataFlow.cs:147:37:147:41 | access to local variable sink9 | LocalDataFlow.cs:149:44:149:48 | access to local variable sink9 | -| LocalDataFlow.cs:149:13:149:49 | SSA def(sink17) | LocalDataFlow.cs:150:15:150:20 | access to local variable sink17 | -| LocalDataFlow.cs:149:22:149:29 | [post] access to local variable nonSink0 | LocalDataFlow.cs:151:36:151:43 | access to local variable nonSink0 | -| LocalDataFlow.cs:149:22:149:29 | access to local variable nonSink0 | LocalDataFlow.cs:151:36:151:43 | access to local variable nonSink0 | -| LocalDataFlow.cs:149:22:149:49 | call to method Replace | LocalDataFlow.cs:149:13:149:49 | SSA def(sink17) | -| LocalDataFlow.cs:149:44:149:48 | [post] access to local variable sink9 | LocalDataFlow.cs:151:46:151:50 | access to local variable sink9 | -| LocalDataFlow.cs:149:44:149:48 | access to local variable sink9 | LocalDataFlow.cs:151:46:151:50 | access to local variable sink9 | -| LocalDataFlow.cs:151:13:151:51 | SSA def(sink18) | LocalDataFlow.cs:152:15:152:20 | access to local variable sink18 | -| LocalDataFlow.cs:151:22:151:51 | call to method Format | LocalDataFlow.cs:151:13:151:51 | SSA def(sink18) | -| LocalDataFlow.cs:151:36:151:43 | [post] access to local variable nonSink0 | LocalDataFlow.cs:153:44:153:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:151:36:151:43 | access to local variable nonSink0 | LocalDataFlow.cs:153:44:153:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:151:46:151:50 | [post] access to local variable sink9 | LocalDataFlow.cs:155:33:155:37 | access to local variable sink9 | -| LocalDataFlow.cs:151:46:151:50 | access to local variable sink9 | LocalDataFlow.cs:155:33:155:37 | access to local variable sink9 | -| LocalDataFlow.cs:152:15:152:20 | [post] access to local variable sink18 | LocalDataFlow.cs:153:36:153:41 | access to local variable sink18 | -| LocalDataFlow.cs:152:15:152:20 | access to local variable sink18 | LocalDataFlow.cs:153:36:153:41 | access to local variable sink18 | -| LocalDataFlow.cs:153:13:153:52 | SSA def(sink19) | LocalDataFlow.cs:154:15:154:20 | access to local variable sink19 | -| LocalDataFlow.cs:153:22:153:52 | call to method Format | LocalDataFlow.cs:153:13:153:52 | SSA def(sink19) | -| LocalDataFlow.cs:153:44:153:51 | [post] access to local variable nonSink0 | LocalDataFlow.cs:172:32:172:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:153:44:153:51 | access to local variable nonSink0 | LocalDataFlow.cs:172:32:172:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:155:13:155:38 | SSA def(sink45) | LocalDataFlow.cs:156:15:156:20 | access to local variable sink45 | -| LocalDataFlow.cs:155:22:155:38 | call to method Parse | LocalDataFlow.cs:155:13:155:38 | SSA def(sink45) | -| LocalDataFlow.cs:155:33:155:37 | [post] access to local variable sink9 | LocalDataFlow.cs:158:36:158:40 | access to local variable sink9 | -| LocalDataFlow.cs:155:33:155:37 | access to local variable sink9 | LocalDataFlow.cs:158:36:158:40 | access to local variable sink9 | -| LocalDataFlow.cs:158:13:158:56 | SSA def(sink46) | LocalDataFlow.cs:159:15:159:20 | access to local variable sink46 | -| LocalDataFlow.cs:158:22:158:56 | call to method TryParse | LocalDataFlow.cs:158:13:158:56 | SSA def(sink46) | -| LocalDataFlow.cs:158:36:158:40 | [post] access to local variable sink9 | LocalDataFlow.cs:198:22:198:26 | access to local variable sink9 | -| LocalDataFlow.cs:158:36:158:40 | access to local variable sink9 | LocalDataFlow.cs:198:22:198:26 | access to local variable sink9 | -| LocalDataFlow.cs:159:15:159:20 | access to local variable sink46 | LocalDataFlow.cs:160:37:160:42 | access to local variable sink46 | -| LocalDataFlow.cs:160:13:160:43 | SSA def(sink47) | LocalDataFlow.cs:161:15:161:20 | access to local variable sink47 | -| LocalDataFlow.cs:160:22:160:43 | call to method ToByte | LocalDataFlow.cs:160:13:160:43 | SSA def(sink47) | -| LocalDataFlow.cs:161:15:161:20 | access to local variable sink47 | LocalDataFlow.cs:162:40:162:45 | access to local variable sink47 | -| LocalDataFlow.cs:162:13:162:46 | SSA def(sink49) | LocalDataFlow.cs:163:15:163:20 | access to local variable sink49 | -| LocalDataFlow.cs:162:22:162:46 | call to method Concat | LocalDataFlow.cs:162:13:162:46 | SSA def(sink49) | -| LocalDataFlow.cs:162:40:162:45 | access to local variable sink47 | LocalDataFlow.cs:162:40:162:45 | (...) ... | -| LocalDataFlow.cs:163:15:163:20 | [post] access to local variable sink49 | LocalDataFlow.cs:164:34:164:39 | access to local variable sink49 | -| LocalDataFlow.cs:163:15:163:20 | access to local variable sink49 | LocalDataFlow.cs:164:34:164:39 | access to local variable sink49 | -| LocalDataFlow.cs:164:13:164:40 | SSA def(sink50) | LocalDataFlow.cs:165:15:165:20 | access to local variable sink50 | -| LocalDataFlow.cs:164:22:164:40 | call to method Copy | LocalDataFlow.cs:164:13:164:40 | SSA def(sink50) | -| LocalDataFlow.cs:164:34:164:39 | access to local variable sink49 | LocalDataFlow.cs:164:22:164:40 | call to method Copy | -| LocalDataFlow.cs:165:15:165:20 | [post] access to local variable sink50 | LocalDataFlow.cs:166:44:166:49 | access to local variable sink50 | -| LocalDataFlow.cs:165:15:165:20 | access to local variable sink50 | LocalDataFlow.cs:166:44:166:49 | access to local variable sink50 | -| LocalDataFlow.cs:166:13:166:54 | SSA def(sink51) | LocalDataFlow.cs:167:15:167:20 | access to local variable sink51 | -| LocalDataFlow.cs:166:22:166:54 | call to method Join | LocalDataFlow.cs:166:13:166:54 | SSA def(sink51) | -| LocalDataFlow.cs:167:15:167:20 | [post] access to local variable sink51 | LocalDataFlow.cs:168:35:168:40 | access to local variable sink51 | -| LocalDataFlow.cs:167:15:167:20 | access to local variable sink51 | LocalDataFlow.cs:168:35:168:40 | access to local variable sink51 | -| LocalDataFlow.cs:168:13:168:41 | SSA def(sink52) | LocalDataFlow.cs:169:15:169:20 | access to local variable sink52 | -| LocalDataFlow.cs:168:22:168:41 | call to method Insert | LocalDataFlow.cs:168:13:168:41 | SSA def(sink52) | -| LocalDataFlow.cs:172:9:172:40 | SSA def(nonSink2) | LocalDataFlow.cs:173:15:173:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:172:20:172:40 | call to method Parse | LocalDataFlow.cs:172:9:172:40 | SSA def(nonSink2) | -| LocalDataFlow.cs:172:32:172:39 | [post] access to local variable nonSink0 | LocalDataFlow.cs:174:39:174:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:172:32:172:39 | access to local variable nonSink0 | LocalDataFlow.cs:174:39:174:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:174:13:174:61 | SSA def(nonSink7) | LocalDataFlow.cs:175:15:175:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:174:24:174:61 | call to method TryParse | LocalDataFlow.cs:174:13:174:61 | SSA def(nonSink7) | -| LocalDataFlow.cs:174:39:174:46 | [post] access to local variable nonSink0 | LocalDataFlow.cs:176:20:176:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:174:39:174:46 | access to local variable nonSink0 | LocalDataFlow.cs:176:20:176:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:176:9:176:50 | SSA def(nonSink0) | LocalDataFlow.cs:177:15:177:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:176:20:176:27 | [post] access to local variable nonSink0 | LocalDataFlow.cs:176:42:176:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:176:20:176:27 | access to local variable nonSink0 | LocalDataFlow.cs:176:42:176:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:176:20:176:50 | call to method Replace | LocalDataFlow.cs:176:9:176:50 | SSA def(nonSink0) | -| LocalDataFlow.cs:177:15:177:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:178:34:178:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:177:15:177:22 | access to local variable nonSink0 | LocalDataFlow.cs:178:34:178:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:178:9:178:52 | SSA def(nonSink0) | LocalDataFlow.cs:179:15:179:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:178:20:178:52 | call to method Format | LocalDataFlow.cs:178:9:178:52 | SSA def(nonSink0) | -| LocalDataFlow.cs:178:34:178:41 | [post] access to local variable nonSink0 | LocalDataFlow.cs:178:44:178:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:178:34:178:41 | access to local variable nonSink0 | LocalDataFlow.cs:178:44:178:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:179:15:179:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:180:31:180:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:179:15:179:22 | access to local variable nonSink0 | LocalDataFlow.cs:180:31:180:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:180:9:180:39 | SSA def(nonSink7) | LocalDataFlow.cs:181:15:181:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:180:20:180:39 | call to method Parse | LocalDataFlow.cs:180:9:180:39 | SSA def(nonSink7) | -| LocalDataFlow.cs:180:31:180:38 | [post] access to local variable nonSink0 | LocalDataFlow.cs:182:34:182:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:180:31:180:38 | access to local variable nonSink0 | LocalDataFlow.cs:182:34:182:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:182:9:182:57 | SSA def(nonSink7) | LocalDataFlow.cs:183:15:183:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:182:20:182:57 | call to method TryParse | LocalDataFlow.cs:182:9:182:57 | SSA def(nonSink7) | -| LocalDataFlow.cs:183:15:183:22 | access to local variable nonSink7 | LocalDataFlow.cs:184:40:184:47 | access to local variable nonSink7 | -| LocalDataFlow.cs:184:13:184:48 | SSA def(nonSink14) | LocalDataFlow.cs:185:15:185:23 | access to local variable nonSink14 | -| LocalDataFlow.cs:184:25:184:48 | call to method ToByte | LocalDataFlow.cs:184:13:184:48 | SSA def(nonSink14) | -| LocalDataFlow.cs:184:40:184:47 | access to local variable nonSink7 | LocalDataFlow.cs:186:38:186:45 | access to local variable nonSink7 | -| LocalDataFlow.cs:186:9:186:46 | SSA def(nonSink0) | LocalDataFlow.cs:187:15:187:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:186:20:186:46 | call to method Concat | LocalDataFlow.cs:186:9:186:46 | SSA def(nonSink0) | -| LocalDataFlow.cs:186:38:186:45 | access to local variable nonSink7 | LocalDataFlow.cs:186:38:186:45 | (...) ... | -| LocalDataFlow.cs:187:15:187:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:188:32:188:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:187:15:187:22 | access to local variable nonSink0 | LocalDataFlow.cs:188:32:188:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:188:9:188:40 | SSA def(nonSink0) | LocalDataFlow.cs:189:15:189:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:188:20:188:40 | call to method Copy | LocalDataFlow.cs:188:9:188:40 | SSA def(nonSink0) | -| LocalDataFlow.cs:188:32:188:39 | access to local variable nonSink0 | LocalDataFlow.cs:188:20:188:40 | call to method Copy | -| LocalDataFlow.cs:189:15:189:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:190:42:190:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:189:15:189:22 | access to local variable nonSink0 | LocalDataFlow.cs:190:42:190:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:190:9:190:54 | SSA def(nonSink0) | LocalDataFlow.cs:191:15:191:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:190:20:190:54 | call to method Join | LocalDataFlow.cs:190:9:190:54 | SSA def(nonSink0) | -| LocalDataFlow.cs:191:15:191:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:192:33:192:40 | access to local variable nonSink0 | -| LocalDataFlow.cs:191:15:191:22 | access to local variable nonSink0 | LocalDataFlow.cs:192:33:192:40 | access to local variable nonSink0 | -| LocalDataFlow.cs:192:9:192:41 | SSA def(nonSink0) | LocalDataFlow.cs:193:15:193:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:192:20:192:41 | call to method Insert | LocalDataFlow.cs:192:9:192:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:196:13:196:32 | SSA def(sink20) | LocalDataFlow.cs:197:15:197:20 | access to local variable sink20 | -| LocalDataFlow.cs:196:22:196:32 | ... > ... | LocalDataFlow.cs:196:13:196:32 | SSA def(sink20) | -| LocalDataFlow.cs:197:15:197:20 | access to local variable sink20 | LocalDataFlow.cs:226:22:226:27 | access to local variable sink20 | -| LocalDataFlow.cs:198:13:198:40 | SSA def(sink21) | LocalDataFlow.cs:199:15:199:20 | access to local variable sink21 | -| LocalDataFlow.cs:198:22:198:40 | call to method Equals | LocalDataFlow.cs:198:13:198:40 | SSA def(sink21) | -| LocalDataFlow.cs:200:13:200:45 | SSA def(sink22) | LocalDataFlow.cs:201:15:201:20 | access to local variable sink22 | -| LocalDataFlow.cs:200:22:200:26 | [post] access to local variable sink8 | LocalDataFlow.cs:206:20:206:24 | access to local variable sink8 | -| LocalDataFlow.cs:200:22:200:26 | access to local variable sink8 | LocalDataFlow.cs:206:20:206:24 | access to local variable sink8 | -| LocalDataFlow.cs:200:22:200:45 | call to method Equals | LocalDataFlow.cs:200:13:200:45 | SSA def(sink22) | -| LocalDataFlow.cs:200:43:200:44 | 41 | LocalDataFlow.cs:200:35:200:44 | (...) ... | -| LocalDataFlow.cs:204:9:204:38 | SSA def(nonSink7) | LocalDataFlow.cs:205:15:205:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:204:20:204:24 | [post] access to local variable sink0 | LocalDataFlow.cs:411:30:411:34 | access to local variable sink0 | -| LocalDataFlow.cs:204:20:204:24 | access to local variable sink0 | LocalDataFlow.cs:411:30:411:34 | access to local variable sink0 | -| LocalDataFlow.cs:204:20:204:38 | call to method Equals | LocalDataFlow.cs:204:9:204:38 | SSA def(nonSink7) | -| LocalDataFlow.cs:204:33:204:37 | [post] access to local variable sink1 | LocalDataFlow.cs:320:22:320:26 | access to local variable sink1 | -| LocalDataFlow.cs:204:33:204:37 | access to local variable sink1 | LocalDataFlow.cs:320:22:320:26 | access to local variable sink1 | -| LocalDataFlow.cs:206:9:206:41 | SSA def(nonSink7) | LocalDataFlow.cs:207:15:207:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:206:20:206:41 | call to method Equals | LocalDataFlow.cs:206:9:206:41 | SSA def(nonSink7) | -| LocalDataFlow.cs:207:15:207:22 | access to local variable nonSink7 | LocalDataFlow.cs:230:20:230:27 | access to local variable nonSink7 | -| LocalDataFlow.cs:210:13:210:31 | SSA def(sink23) | LocalDataFlow.cs:211:15:211:20 | access to local variable sink23 | -| LocalDataFlow.cs:210:22:210:31 | access to indexer | LocalDataFlow.cs:210:13:210:31 | SSA def(sink23) | -| LocalDataFlow.cs:211:15:211:20 | [post] access to local variable sink23 | LocalDataFlow.cs:234:37:234:42 | access to local variable sink23 | -| LocalDataFlow.cs:211:15:211:20 | access to local variable sink23 | LocalDataFlow.cs:234:37:234:42 | access to local variable sink23 | -| LocalDataFlow.cs:214:9:214:31 | SSA def(nonSink0) | LocalDataFlow.cs:215:15:215:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:214:20:214:27 | [post] access to local variable nonSink1 | LocalDataFlow.cs:328:9:328:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink1 | LocalDataFlow.cs:328:9:328:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:214:20:214:31 | access to indexer | LocalDataFlow.cs:214:9:214:31 | SSA def(nonSink0) | -| LocalDataFlow.cs:215:15:215:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:246:39:246:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:215:15:215:22 | access to local variable nonSink0 | LocalDataFlow.cs:246:39:246:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:218:13:218:30 | SSA def(sink24) | LocalDataFlow.cs:219:15:219:20 | access to local variable sink24 | -| LocalDataFlow.cs:218:22:218:27 | access to local variable sink10 | LocalDataFlow.cs:363:32:363:37 | access to local variable sink10 | -| LocalDataFlow.cs:218:22:218:30 | access to array element | LocalDataFlow.cs:218:13:218:30 | SSA def(sink24) | -| LocalDataFlow.cs:222:9:222:30 | SSA def(nonSink3) | LocalDataFlow.cs:223:15:223:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:222:20:222:27 | access to local variable nonSink4 | LocalDataFlow.cs:377:35:377:42 | access to local variable nonSink4 | -| LocalDataFlow.cs:222:20:222:30 | access to array element | LocalDataFlow.cs:222:9:222:30 | SSA def(nonSink3) | -| LocalDataFlow.cs:226:13:226:36 | SSA def(sink25) | LocalDataFlow.cs:227:15:227:20 | access to local variable sink25 | -| LocalDataFlow.cs:226:22:226:36 | ... \|\| ... | LocalDataFlow.cs:226:13:226:36 | SSA def(sink25) | -| LocalDataFlow.cs:230:9:230:36 | SSA def(nonSink7) | LocalDataFlow.cs:231:15:231:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:230:20:230:36 | ... \|\| ... | LocalDataFlow.cs:230:9:230:36 | SSA def(nonSink7) | -| LocalDataFlow.cs:234:13:234:43 | SSA def(sink26) | LocalDataFlow.cs:235:15:235:20 | access to local variable sink26 | -| LocalDataFlow.cs:234:22:234:43 | object creation of type Uri | LocalDataFlow.cs:234:13:234:43 | SSA def(sink26) | -| LocalDataFlow.cs:235:15:235:20 | [post] access to local variable sink26 | LocalDataFlow.cs:236:22:236:27 | access to local variable sink26 | -| LocalDataFlow.cs:235:15:235:20 | access to local variable sink26 | LocalDataFlow.cs:236:22:236:27 | access to local variable sink26 | -| LocalDataFlow.cs:236:13:236:38 | SSA def(sink27) | LocalDataFlow.cs:237:15:237:20 | access to local variable sink27 | -| LocalDataFlow.cs:236:22:236:27 | [post] access to local variable sink26 | LocalDataFlow.cs:238:22:238:27 | access to local variable sink26 | -| LocalDataFlow.cs:236:22:236:27 | access to local variable sink26 | LocalDataFlow.cs:238:22:238:27 | access to local variable sink26 | -| LocalDataFlow.cs:236:22:236:38 | call to method ToString | LocalDataFlow.cs:236:13:236:38 | SSA def(sink27) | -| LocalDataFlow.cs:238:13:238:40 | SSA def(sink28) | LocalDataFlow.cs:239:15:239:20 | access to local variable sink28 | -| LocalDataFlow.cs:238:22:238:27 | [post] access to local variable sink26 | LocalDataFlow.cs:240:22:240:27 | access to local variable sink26 | -| LocalDataFlow.cs:238:22:238:27 | access to local variable sink26 | LocalDataFlow.cs:240:22:240:27 | access to local variable sink26 | -| LocalDataFlow.cs:238:22:238:40 | access to property PathAndQuery | LocalDataFlow.cs:238:13:238:40 | SSA def(sink28) | -| LocalDataFlow.cs:240:13:240:33 | SSA def(sink29) | LocalDataFlow.cs:241:15:241:20 | access to local variable sink29 | -| LocalDataFlow.cs:240:22:240:27 | [post] access to local variable sink26 | LocalDataFlow.cs:242:22:242:27 | access to local variable sink26 | -| LocalDataFlow.cs:240:22:240:27 | access to local variable sink26 | LocalDataFlow.cs:242:22:242:27 | access to local variable sink26 | -| LocalDataFlow.cs:240:22:240:33 | access to property Query | LocalDataFlow.cs:240:13:240:33 | SSA def(sink29) | -| LocalDataFlow.cs:242:13:242:42 | SSA def(sink30) | LocalDataFlow.cs:243:15:243:20 | access to local variable sink30 | -| LocalDataFlow.cs:242:22:242:42 | access to property OriginalString | LocalDataFlow.cs:242:13:242:42 | SSA def(sink30) | -| LocalDataFlow.cs:243:15:243:20 | [post] access to local variable sink30 | LocalDataFlow.cs:258:49:258:54 | access to local variable sink30 | -| LocalDataFlow.cs:243:15:243:20 | access to local variable sink30 | LocalDataFlow.cs:258:49:258:54 | access to local variable sink30 | -| LocalDataFlow.cs:246:13:246:47 | SSA def(nonSink8) | LocalDataFlow.cs:247:15:247:22 | access to local variable nonSink8 | -| LocalDataFlow.cs:246:24:246:47 | object creation of type Uri | LocalDataFlow.cs:246:13:246:47 | SSA def(nonSink8) | -| LocalDataFlow.cs:247:15:247:22 | [post] access to local variable nonSink8 | LocalDataFlow.cs:248:20:248:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:247:15:247:22 | access to local variable nonSink8 | LocalDataFlow.cs:248:20:248:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:248:9:248:38 | SSA def(nonSink0) | LocalDataFlow.cs:249:15:249:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:248:20:248:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:250:20:250:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:248:20:248:27 | access to local variable nonSink8 | LocalDataFlow.cs:250:20:250:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:248:20:248:38 | call to method ToString | LocalDataFlow.cs:248:9:248:38 | SSA def(nonSink0) | -| LocalDataFlow.cs:250:9:250:40 | SSA def(nonSink0) | LocalDataFlow.cs:251:15:251:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:250:20:250:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:252:20:252:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:250:20:250:27 | access to local variable nonSink8 | LocalDataFlow.cs:252:20:252:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:250:20:250:40 | access to property PathAndQuery | LocalDataFlow.cs:250:9:250:40 | SSA def(nonSink0) | -| LocalDataFlow.cs:252:9:252:33 | SSA def(nonSink0) | LocalDataFlow.cs:253:15:253:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:252:20:252:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:254:20:254:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:252:20:252:27 | access to local variable nonSink8 | LocalDataFlow.cs:254:20:254:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:252:20:252:33 | access to property Query | LocalDataFlow.cs:252:9:252:33 | SSA def(nonSink0) | -| LocalDataFlow.cs:254:9:254:42 | SSA def(nonSink0) | LocalDataFlow.cs:255:15:255:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:254:20:254:42 | access to property OriginalString | LocalDataFlow.cs:254:9:254:42 | SSA def(nonSink0) | -| LocalDataFlow.cs:255:15:255:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:264:51:264:58 | access to local variable nonSink0 | -| LocalDataFlow.cs:255:15:255:22 | access to local variable nonSink0 | LocalDataFlow.cs:264:51:264:58 | access to local variable nonSink0 | -| LocalDataFlow.cs:258:13:258:55 | SSA def(sink31) | LocalDataFlow.cs:259:15:259:20 | access to local variable sink31 | -| LocalDataFlow.cs:258:22:258:55 | object creation of type StringReader | LocalDataFlow.cs:258:13:258:55 | SSA def(sink31) | -| LocalDataFlow.cs:259:15:259:20 | [post] access to local variable sink31 | LocalDataFlow.cs:260:22:260:27 | access to local variable sink31 | -| LocalDataFlow.cs:259:15:259:20 | access to local variable sink31 | LocalDataFlow.cs:260:22:260:27 | access to local variable sink31 | -| LocalDataFlow.cs:260:13:260:39 | SSA def(sink32) | LocalDataFlow.cs:261:15:261:20 | access to local variable sink32 | -| LocalDataFlow.cs:260:22:260:39 | call to method ReadToEnd | LocalDataFlow.cs:260:13:260:39 | SSA def(sink32) | -| LocalDataFlow.cs:261:15:261:20 | [post] access to local variable sink32 | LocalDataFlow.cs:270:30:270:35 | access to local variable sink32 | -| LocalDataFlow.cs:261:15:261:20 | access to local variable sink32 | LocalDataFlow.cs:270:30:270:35 | access to local variable sink32 | -| LocalDataFlow.cs:264:13:264:59 | SSA def(nonSink9) | LocalDataFlow.cs:265:15:265:22 | access to local variable nonSink9 | -| LocalDataFlow.cs:264:24:264:59 | object creation of type StringReader | LocalDataFlow.cs:264:13:264:59 | SSA def(nonSink9) | -| LocalDataFlow.cs:265:15:265:22 | [post] access to local variable nonSink9 | LocalDataFlow.cs:266:20:266:27 | access to local variable nonSink9 | -| LocalDataFlow.cs:265:15:265:22 | access to local variable nonSink9 | LocalDataFlow.cs:266:20:266:27 | access to local variable nonSink9 | -| LocalDataFlow.cs:266:9:266:39 | SSA def(nonSink0) | LocalDataFlow.cs:267:15:267:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:266:20:266:39 | call to method ReadToEnd | LocalDataFlow.cs:266:9:266:39 | SSA def(nonSink0) | -| LocalDataFlow.cs:267:15:267:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:276:28:276:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:267:15:267:22 | access to local variable nonSink0 | LocalDataFlow.cs:276:28:276:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:270:13:270:127 | SSA def(sink33) | LocalDataFlow.cs:271:15:271:20 | access to local variable sink33 | -| LocalDataFlow.cs:270:22:270:127 | (...) ... | LocalDataFlow.cs:270:13:270:127 | SSA def(sink33) | -| LocalDataFlow.cs:270:30:270:119 | call to method Insert | LocalDataFlow.cs:270:30:270:127 | call to method Clone | -| LocalDataFlow.cs:270:30:270:127 | call to method Clone | LocalDataFlow.cs:270:22:270:127 | (...) ... | -| LocalDataFlow.cs:271:15:271:20 | [post] access to local variable sink33 | LocalDataFlow.cs:272:22:272:27 | access to local variable sink33 | -| LocalDataFlow.cs:271:15:271:20 | access to local variable sink33 | LocalDataFlow.cs:272:22:272:27 | access to local variable sink33 | -| LocalDataFlow.cs:272:13:272:63 | SSA def(sink48) | LocalDataFlow.cs:273:15:273:20 | access to local variable sink48 | -| LocalDataFlow.cs:272:22:272:27 | [post] access to local variable sink33 | LocalDataFlow.cs:282:40:282:45 | access to local variable sink33 | -| LocalDataFlow.cs:272:22:272:27 | access to local variable sink33 | LocalDataFlow.cs:282:40:282:45 | access to local variable sink33 | -| LocalDataFlow.cs:272:22:272:63 | call to method Split | LocalDataFlow.cs:272:13:272:63 | SSA def(sink48) | -| LocalDataFlow.cs:276:9:276:127 | SSA def(nonSink0) | LocalDataFlow.cs:277:15:277:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:276:20:276:127 | (...) ... | LocalDataFlow.cs:276:9:276:127 | SSA def(nonSink0) | -| LocalDataFlow.cs:276:28:276:119 | call to method Insert | LocalDataFlow.cs:276:28:276:127 | call to method Clone | -| LocalDataFlow.cs:276:28:276:127 | call to method Clone | LocalDataFlow.cs:276:20:276:127 | (...) ... | -| LocalDataFlow.cs:277:15:277:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:278:25:278:32 | access to local variable nonSink0 | -| LocalDataFlow.cs:277:15:277:22 | access to local variable nonSink0 | LocalDataFlow.cs:278:25:278:32 | access to local variable nonSink0 | -| LocalDataFlow.cs:278:13:278:68 | SSA def(nonSink15) | LocalDataFlow.cs:279:15:279:23 | access to local variable nonSink15 | -| LocalDataFlow.cs:278:25:278:32 | [post] access to local variable nonSink0 | LocalDataFlow.cs:291:43:291:50 | access to local variable nonSink0 | -| LocalDataFlow.cs:278:25:278:32 | access to local variable nonSink0 | LocalDataFlow.cs:291:43:291:50 | access to local variable nonSink0 | -| LocalDataFlow.cs:278:25:278:68 | call to method Split | LocalDataFlow.cs:278:13:278:68 | SSA def(nonSink15) | -| LocalDataFlow.cs:282:13:282:46 | SSA def(sink34) | LocalDataFlow.cs:283:15:283:20 | access to local variable sink34 | -| LocalDataFlow.cs:282:22:282:46 | object creation of type StringBuilder | LocalDataFlow.cs:282:13:282:46 | SSA def(sink34) | -| LocalDataFlow.cs:283:15:283:20 | [post] access to local variable sink34 | LocalDataFlow.cs:284:22:284:27 | access to local variable sink34 | -| LocalDataFlow.cs:283:15:283:20 | access to local variable sink34 | LocalDataFlow.cs:284:22:284:27 | access to local variable sink34 | -| LocalDataFlow.cs:284:13:284:38 | SSA def(sink35) | LocalDataFlow.cs:285:15:285:20 | access to local variable sink35 | -| LocalDataFlow.cs:284:22:284:38 | call to method ToString | LocalDataFlow.cs:284:13:284:38 | SSA def(sink35) | -| LocalDataFlow.cs:285:15:285:20 | [post] access to local variable sink35 | LocalDataFlow.cs:287:27:287:32 | access to local variable sink35 | -| LocalDataFlow.cs:285:15:285:20 | access to local variable sink35 | LocalDataFlow.cs:287:27:287:32 | access to local variable sink35 | -| LocalDataFlow.cs:286:13:286:42 | SSA def(sink36) | LocalDataFlow.cs:287:9:287:14 | access to local variable sink36 | -| LocalDataFlow.cs:286:22:286:42 | object creation of type StringBuilder | LocalDataFlow.cs:286:13:286:42 | SSA def(sink36) | -| LocalDataFlow.cs:287:9:287:14 | [post] access to local variable sink36 | LocalDataFlow.cs:288:15:288:20 | access to local variable sink36 | -| LocalDataFlow.cs:287:9:287:14 | access to local variable sink36 | LocalDataFlow.cs:288:15:288:20 | access to local variable sink36 | -| LocalDataFlow.cs:291:13:291:51 | SSA def(nonSink10) | LocalDataFlow.cs:292:15:292:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:291:25:291:51 | object creation of type StringBuilder | LocalDataFlow.cs:291:13:291:51 | SSA def(nonSink10) | -| LocalDataFlow.cs:292:15:292:23 | [post] access to local variable nonSink10 | LocalDataFlow.cs:293:20:293:28 | access to local variable nonSink10 | -| LocalDataFlow.cs:292:15:292:23 | access to local variable nonSink10 | LocalDataFlow.cs:293:20:293:28 | access to local variable nonSink10 | -| LocalDataFlow.cs:293:9:293:39 | SSA def(nonSink0) | LocalDataFlow.cs:294:15:294:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:293:20:293:28 | [post] access to local variable nonSink10 | LocalDataFlow.cs:295:9:295:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:293:20:293:28 | access to local variable nonSink10 | LocalDataFlow.cs:295:9:295:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:293:20:293:39 | call to method ToString | LocalDataFlow.cs:293:9:293:39 | SSA def(nonSink0) | -| LocalDataFlow.cs:294:15:294:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:295:30:295:37 | access to local variable nonSink0 | -| LocalDataFlow.cs:294:15:294:22 | access to local variable nonSink0 | LocalDataFlow.cs:295:30:295:37 | access to local variable nonSink0 | -| LocalDataFlow.cs:295:9:295:17 | [post] access to local variable nonSink10 | LocalDataFlow.cs:296:15:296:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:295:9:295:17 | access to local variable nonSink10 | LocalDataFlow.cs:296:15:296:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:299:13:299:52 | SSA def(sink40) | LocalDataFlow.cs:300:15:300:20 | access to local variable sink40 | -| LocalDataFlow.cs:299:22:299:52 | object creation of type Lazy | LocalDataFlow.cs:299:13:299:52 | SSA def(sink40) | -| LocalDataFlow.cs:299:39:299:51 | [output] delegate creation of type Func | LocalDataFlow.cs:299:22:299:52 | object creation of type Lazy | -| LocalDataFlow.cs:299:39:299:51 | this access | LocalDataFlow.cs:309:42:309:57 | this access | -| LocalDataFlow.cs:300:15:300:20 | [post] access to local variable sink40 | LocalDataFlow.cs:301:22:301:27 | access to local variable sink40 | -| LocalDataFlow.cs:300:15:300:20 | access to local variable sink40 | LocalDataFlow.cs:301:22:301:27 | access to local variable sink40 | -| LocalDataFlow.cs:301:13:301:33 | SSA def(sink41) | LocalDataFlow.cs:302:15:302:20 | access to local variable sink41 | -| LocalDataFlow.cs:301:22:301:27 | access to local variable sink40 | LocalDataFlow.cs:301:22:301:33 | access to property Value | -| LocalDataFlow.cs:301:22:301:33 | access to property Value | LocalDataFlow.cs:301:13:301:33 | SSA def(sink41) | -| LocalDataFlow.cs:303:13:303:59 | SSA def(sink42) | LocalDataFlow.cs:304:15:304:20 | access to local variable sink42 | -| LocalDataFlow.cs:303:22:303:59 | object creation of type Lazy | LocalDataFlow.cs:303:13:303:59 | SSA def(sink42) | -| LocalDataFlow.cs:303:39:303:58 | [output] (...) => ... | LocalDataFlow.cs:303:22:303:59 | object creation of type Lazy | -| LocalDataFlow.cs:304:15:304:20 | [post] access to local variable sink42 | LocalDataFlow.cs:305:22:305:27 | access to local variable sink42 | -| LocalDataFlow.cs:304:15:304:20 | access to local variable sink42 | LocalDataFlow.cs:305:22:305:27 | access to local variable sink42 | -| LocalDataFlow.cs:305:13:305:33 | SSA def(sink43) | LocalDataFlow.cs:306:15:306:20 | access to local variable sink43 | -| LocalDataFlow.cs:305:22:305:27 | access to local variable sink42 | LocalDataFlow.cs:305:22:305:33 | access to property Value | -| LocalDataFlow.cs:305:22:305:33 | access to property Value | LocalDataFlow.cs:305:13:305:33 | SSA def(sink43) | -| LocalDataFlow.cs:309:13:309:58 | SSA def(nonSink12) | LocalDataFlow.cs:310:15:310:23 | access to local variable nonSink12 | -| LocalDataFlow.cs:309:25:309:58 | object creation of type Lazy | LocalDataFlow.cs:309:13:309:58 | SSA def(nonSink12) | -| LocalDataFlow.cs:309:42:309:57 | [output] delegate creation of type Func | LocalDataFlow.cs:309:25:309:58 | object creation of type Lazy | -| LocalDataFlow.cs:310:15:310:23 | [post] access to local variable nonSink12 | LocalDataFlow.cs:311:20:311:28 | access to local variable nonSink12 | -| LocalDataFlow.cs:310:15:310:23 | access to local variable nonSink12 | LocalDataFlow.cs:311:20:311:28 | access to local variable nonSink12 | -| LocalDataFlow.cs:311:9:311:34 | SSA def(nonSink0) | LocalDataFlow.cs:312:15:312:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:311:20:311:28 | access to local variable nonSink12 | LocalDataFlow.cs:311:20:311:34 | access to property Value | -| LocalDataFlow.cs:311:20:311:34 | access to property Value | LocalDataFlow.cs:311:9:311:34 | SSA def(nonSink0) | -| LocalDataFlow.cs:313:9:313:46 | SSA def(nonSink12) | LocalDataFlow.cs:314:15:314:23 | access to local variable nonSink12 | -| LocalDataFlow.cs:313:21:313:46 | object creation of type Lazy | LocalDataFlow.cs:313:9:313:46 | SSA def(nonSink12) | -| LocalDataFlow.cs:313:38:313:45 | [output] (...) => ... | LocalDataFlow.cs:313:21:313:46 | object creation of type Lazy | -| LocalDataFlow.cs:314:15:314:23 | [post] access to local variable nonSink12 | LocalDataFlow.cs:315:20:315:28 | access to local variable nonSink12 | -| LocalDataFlow.cs:314:15:314:23 | access to local variable nonSink12 | LocalDataFlow.cs:315:20:315:28 | access to local variable nonSink12 | -| LocalDataFlow.cs:315:9:315:34 | SSA def(nonSink0) | LocalDataFlow.cs:316:15:316:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:315:20:315:28 | access to local variable nonSink12 | LocalDataFlow.cs:315:20:315:34 | access to property Value | -| LocalDataFlow.cs:315:20:315:34 | access to property Value | LocalDataFlow.cs:315:9:315:34 | SSA def(nonSink0) | -| LocalDataFlow.cs:316:15:316:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:328:26:328:33 | access to local variable nonSink0 | -| LocalDataFlow.cs:316:15:316:22 | access to local variable nonSink0 | LocalDataFlow.cs:328:26:328:33 | access to local variable nonSink0 | -| LocalDataFlow.cs:319:13:319:49 | SSA def(sink3) | LocalDataFlow.cs:320:9:320:13 | access to local variable sink3 | -| LocalDataFlow.cs:319:21:319:49 | object creation of type Dictionary | LocalDataFlow.cs:319:13:319:49 | SSA def(sink3) | -| LocalDataFlow.cs:320:9:320:13 | [post] access to local variable sink3 | LocalDataFlow.cs:321:15:321:19 | access to local variable sink3 | -| LocalDataFlow.cs:320:9:320:13 | access to local variable sink3 | LocalDataFlow.cs:321:15:321:19 | access to local variable sink3 | -| LocalDataFlow.cs:320:22:320:26 | [post] access to local variable sink1 | LocalDataFlow.cs:329:22:329:26 | access to local variable sink1 | -| LocalDataFlow.cs:320:22:320:26 | access to local variable sink1 | LocalDataFlow.cs:329:22:329:26 | access to local variable sink1 | -| LocalDataFlow.cs:321:15:321:19 | [post] access to local variable sink3 | LocalDataFlow.cs:322:22:322:26 | access to local variable sink3 | -| LocalDataFlow.cs:321:15:321:19 | access to local variable sink3 | LocalDataFlow.cs:322:22:322:26 | access to local variable sink3 | -| LocalDataFlow.cs:322:13:322:33 | SSA def(sink12) | LocalDataFlow.cs:323:15:323:20 | access to local variable sink12 | -| LocalDataFlow.cs:322:22:322:26 | [post] access to local variable sink3 | LocalDataFlow.cs:369:57:369:61 | access to local variable sink3 | -| LocalDataFlow.cs:322:22:322:26 | access to local variable sink3 | LocalDataFlow.cs:369:57:369:61 | access to local variable sink3 | -| LocalDataFlow.cs:322:22:322:33 | access to property Values | LocalDataFlow.cs:322:13:322:33 | SSA def(sink12) | -| LocalDataFlow.cs:323:15:323:20 | [post] access to local variable sink12 | LocalDataFlow.cs:324:22:324:27 | access to local variable sink12 | -| LocalDataFlow.cs:323:15:323:20 | access to local variable sink12 | LocalDataFlow.cs:324:22:324:27 | access to local variable sink12 | -| LocalDataFlow.cs:324:13:324:37 | SSA def(sink13) | LocalDataFlow.cs:325:15:325:20 | access to local variable sink13 | -| LocalDataFlow.cs:324:22:324:37 | call to method Reverse | LocalDataFlow.cs:324:13:324:37 | SSA def(sink13) | -| LocalDataFlow.cs:328:9:328:16 | [post] access to local variable nonSink1 | LocalDataFlow.cs:329:9:329:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:328:9:328:16 | access to local variable nonSink1 | LocalDataFlow.cs:329:9:329:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:329:9:329:16 | [post] access to local variable nonSink1 | LocalDataFlow.cs:330:15:330:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:329:9:329:16 | access to local variable nonSink1 | LocalDataFlow.cs:330:15:330:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:329:22:329:26 | [post] access to local variable sink1 | LocalDataFlow.cs:403:30:403:34 | access to local variable sink1 | -| LocalDataFlow.cs:329:22:329:26 | access to local variable sink1 | LocalDataFlow.cs:403:30:403:34 | access to local variable sink1 | -| LocalDataFlow.cs:330:15:330:22 | [post] access to local variable nonSink1 | LocalDataFlow.cs:331:24:331:31 | access to local variable nonSink1 | -| LocalDataFlow.cs:330:15:330:22 | access to local variable nonSink1 | LocalDataFlow.cs:331:24:331:31 | access to local variable nonSink1 | -| LocalDataFlow.cs:331:13:331:38 | SSA def(nonSink5) | LocalDataFlow.cs:332:15:332:22 | access to local variable nonSink5 | -| LocalDataFlow.cs:331:24:331:31 | [post] access to local variable nonSink1 | LocalDataFlow.cs:383:63:383:70 | access to local variable nonSink1 | -| LocalDataFlow.cs:331:24:331:31 | access to local variable nonSink1 | LocalDataFlow.cs:383:63:383:70 | access to local variable nonSink1 | -| LocalDataFlow.cs:331:24:331:38 | access to property Values | LocalDataFlow.cs:331:13:331:38 | SSA def(nonSink5) | -| LocalDataFlow.cs:332:15:332:22 | [post] access to local variable nonSink5 | LocalDataFlow.cs:333:24:333:31 | access to local variable nonSink5 | -| LocalDataFlow.cs:332:15:332:22 | access to local variable nonSink5 | LocalDataFlow.cs:333:24:333:31 | access to local variable nonSink5 | -| LocalDataFlow.cs:333:13:333:41 | SSA def(nonSink6) | LocalDataFlow.cs:334:15:334:22 | access to local variable nonSink6 | -| LocalDataFlow.cs:333:24:333:41 | call to method Reverse | LocalDataFlow.cs:333:13:333:41 | SSA def(nonSink6) | -| LocalDataFlow.cs:337:13:337:52 | SSA def(taintedDataContract) | LocalDataFlow.cs:338:22:338:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:337:13:337:52 | SSA qualifier def(taintedDataContract.AList) | LocalDataFlow.cs:340:22:340:46 | access to property AList | -| LocalDataFlow.cs:337:35:337:52 | object creation of type DataContract | LocalDataFlow.cs:337:13:337:52 | SSA def(taintedDataContract) | -| LocalDataFlow.cs:338:13:338:48 | SSA def(sink53) | LocalDataFlow.cs:339:15:339:20 | access to local variable sink53 | -| LocalDataFlow.cs:338:22:338:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:340:22:340:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:338:22:338:40 | access to local variable taintedDataContract | LocalDataFlow.cs:340:22:340:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:338:22:338:48 | access to property AString | LocalDataFlow.cs:338:13:338:48 | SSA def(sink53) | -| LocalDataFlow.cs:340:13:340:57 | SSA def(sink54) | LocalDataFlow.cs:341:15:341:20 | access to local variable sink54 | -| LocalDataFlow.cs:340:22:340:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:347:20:347:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:340:22:340:40 | access to local variable taintedDataContract | LocalDataFlow.cs:347:20:347:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:340:22:340:46 | [post] access to property AList | LocalDataFlow.cs:349:20:349:44 | access to property AList | -| LocalDataFlow.cs:340:22:340:46 | access to property AList | LocalDataFlow.cs:349:20:349:44 | access to property AList | -| LocalDataFlow.cs:340:22:340:57 | access to property AString | LocalDataFlow.cs:340:13:340:57 | SSA def(sink54) | -| LocalDataFlow.cs:344:13:344:55 | SSA def(nonTaintedDataContract) | LocalDataFlow.cs:345:20:345:41 | access to local variable nonTaintedDataContract | -| LocalDataFlow.cs:344:38:344:55 | object creation of type DataContract | LocalDataFlow.cs:344:13:344:55 | SSA def(nonTaintedDataContract) | -| LocalDataFlow.cs:345:9:345:49 | SSA def(nonSink0) | LocalDataFlow.cs:346:15:346:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:345:20:345:49 | access to property AString | LocalDataFlow.cs:345:9:345:49 | SSA def(nonSink0) | -| LocalDataFlow.cs:347:9:347:44 | SSA def(nonSink2) | LocalDataFlow.cs:348:15:348:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:347:20:347:38 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:349:20:349:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:347:20:347:38 | access to local variable taintedDataContract | LocalDataFlow.cs:349:20:349:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:347:20:347:44 | access to property AnInt | LocalDataFlow.cs:347:9:347:44 | SSA def(nonSink2) | -| LocalDataFlow.cs:349:9:349:53 | SSA def(nonSink2) | LocalDataFlow.cs:350:15:350:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:349:20:349:53 | access to property AnInt | LocalDataFlow.cs:349:9:349:53 | SSA def(nonSink2) | -| LocalDataFlow.cs:353:17:353:37 | SSA def(taintedTextBox) | LocalDataFlow.cs:354:22:354:35 | access to local variable taintedTextBox | -| LocalDataFlow.cs:353:34:353:37 | null | LocalDataFlow.cs:353:17:353:37 | SSA def(taintedTextBox) | -| LocalDataFlow.cs:354:13:354:40 | SSA def(sink60) | LocalDataFlow.cs:355:15:355:20 | access to local variable sink60 | -| LocalDataFlow.cs:354:22:354:40 | access to property Text | LocalDataFlow.cs:354:13:354:40 | SSA def(sink60) | -| LocalDataFlow.cs:358:17:358:40 | SSA def(nonTaintedTextBox) | LocalDataFlow.cs:359:20:359:36 | access to local variable nonTaintedTextBox | -| LocalDataFlow.cs:358:37:358:40 | null | LocalDataFlow.cs:358:17:358:40 | SSA def(nonTaintedTextBox) | -| LocalDataFlow.cs:359:9:359:41 | SSA def(nonSink0) | LocalDataFlow.cs:360:15:360:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:359:20:359:41 | access to property Text | LocalDataFlow.cs:359:9:359:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:363:22:363:27 | SSA def(sink61) | LocalDataFlow.cs:364:19:364:24 | access to local variable sink61 | -| LocalDataFlow.cs:363:32:363:37 | access to local variable sink10 | LocalDataFlow.cs:365:30:365:35 | access to local variable sink10 | -| LocalDataFlow.cs:365:21:365:51 | SSA def(sink62) | LocalDataFlow.cs:366:15:366:20 | access to local variable sink62 | -| LocalDataFlow.cs:365:30:365:51 | call to method GetEnumerator | LocalDataFlow.cs:365:21:365:51 | SSA def(sink62) | -| LocalDataFlow.cs:366:15:366:20 | [post] access to local variable sink62 | LocalDataFlow.cs:367:22:367:27 | access to local variable sink62 | -| LocalDataFlow.cs:366:15:366:20 | access to local variable sink62 | LocalDataFlow.cs:367:22:367:27 | access to local variable sink62 | -| LocalDataFlow.cs:367:13:367:35 | SSA def(sink63) | LocalDataFlow.cs:368:15:368:20 | access to local variable sink63 | -| LocalDataFlow.cs:367:22:367:27 | access to local variable sink62 | LocalDataFlow.cs:367:22:367:35 | access to property Current | -| LocalDataFlow.cs:367:22:367:35 | access to property Current | LocalDataFlow.cs:367:13:367:35 | SSA def(sink63) | -| LocalDataFlow.cs:369:48:369:77 | SSA def(sink64) | LocalDataFlow.cs:370:15:370:20 | access to local variable sink64 | -| LocalDataFlow.cs:369:57:369:77 | (...) ... | LocalDataFlow.cs:369:48:369:77 | SSA def(sink64) | -| LocalDataFlow.cs:369:57:369:77 | call to method GetEnumerator | LocalDataFlow.cs:369:57:369:77 | (...) ... | -| LocalDataFlow.cs:370:15:370:20 | [post] access to local variable sink64 | LocalDataFlow.cs:371:22:371:27 | access to local variable sink64 | -| LocalDataFlow.cs:370:15:370:20 | access to local variable sink64 | LocalDataFlow.cs:371:22:371:27 | access to local variable sink64 | -| LocalDataFlow.cs:371:13:371:35 | SSA def(sink65) | LocalDataFlow.cs:372:15:372:20 | access to local variable sink65 | -| LocalDataFlow.cs:371:22:371:27 | access to local variable sink64 | LocalDataFlow.cs:371:22:371:35 | access to property Current | -| LocalDataFlow.cs:371:22:371:35 | access to property Current | LocalDataFlow.cs:371:13:371:35 | SSA def(sink65) | -| LocalDataFlow.cs:372:15:372:20 | access to local variable sink65 | LocalDataFlow.cs:373:22:373:27 | access to local variable sink65 | -| LocalDataFlow.cs:373:13:373:33 | SSA def(sink66) | LocalDataFlow.cs:374:15:374:20 | access to local variable sink66 | -| LocalDataFlow.cs:373:22:373:27 | access to local variable sink65 | LocalDataFlow.cs:373:22:373:33 | access to property Value | -| LocalDataFlow.cs:373:22:373:33 | access to property Value | LocalDataFlow.cs:373:13:373:33 | SSA def(sink66) | -| LocalDataFlow.cs:377:22:377:30 | SSA def(nonSink17) | LocalDataFlow.cs:378:19:378:27 | access to local variable nonSink17 | -| LocalDataFlow.cs:377:35:377:42 | access to local variable nonSink4 | LocalDataFlow.cs:379:33:379:40 | access to local variable nonSink4 | -| LocalDataFlow.cs:379:21:379:56 | SSA def(nonSink18) | LocalDataFlow.cs:380:15:380:23 | access to local variable nonSink18 | -| LocalDataFlow.cs:379:33:379:56 | call to method GetEnumerator | LocalDataFlow.cs:379:21:379:56 | SSA def(nonSink18) | -| LocalDataFlow.cs:380:15:380:23 | [post] access to local variable nonSink18 | LocalDataFlow.cs:381:20:381:28 | access to local variable nonSink18 | -| LocalDataFlow.cs:380:15:380:23 | access to local variable nonSink18 | LocalDataFlow.cs:381:20:381:28 | access to local variable nonSink18 | -| LocalDataFlow.cs:381:9:381:36 | SSA def(nonSink3) | LocalDataFlow.cs:382:15:382:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:381:20:381:28 | access to local variable nonSink18 | LocalDataFlow.cs:381:20:381:36 | access to property Current | -| LocalDataFlow.cs:381:20:381:36 | access to property Current | LocalDataFlow.cs:381:9:381:36 | SSA def(nonSink3) | -| LocalDataFlow.cs:383:51:383:86 | SSA def(nonSink19) | LocalDataFlow.cs:384:15:384:23 | access to local variable nonSink19 | -| LocalDataFlow.cs:383:63:383:86 | (...) ... | LocalDataFlow.cs:383:51:383:86 | SSA def(nonSink19) | -| LocalDataFlow.cs:383:63:383:86 | call to method GetEnumerator | LocalDataFlow.cs:383:63:383:86 | (...) ... | -| LocalDataFlow.cs:384:15:384:23 | [post] access to local variable nonSink19 | LocalDataFlow.cs:385:25:385:33 | access to local variable nonSink19 | -| LocalDataFlow.cs:384:15:384:23 | access to local variable nonSink19 | LocalDataFlow.cs:385:25:385:33 | access to local variable nonSink19 | -| LocalDataFlow.cs:385:13:385:41 | SSA def(nonSink20) | LocalDataFlow.cs:386:15:386:23 | access to local variable nonSink20 | -| LocalDataFlow.cs:385:25:385:33 | access to local variable nonSink19 | LocalDataFlow.cs:385:25:385:41 | access to property Current | -| LocalDataFlow.cs:385:25:385:41 | access to property Current | LocalDataFlow.cs:385:13:385:41 | SSA def(nonSink20) | -| LocalDataFlow.cs:386:15:386:23 | access to local variable nonSink20 | LocalDataFlow.cs:387:20:387:28 | access to local variable nonSink20 | -| LocalDataFlow.cs:387:9:387:34 | SSA def(nonSink0) | LocalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:387:20:387:28 | access to local variable nonSink20 | LocalDataFlow.cs:387:20:387:34 | access to property Value | -| LocalDataFlow.cs:387:20:387:34 | access to property Value | LocalDataFlow.cs:387:9:387:34 | SSA def(nonSink0) | -| LocalDataFlow.cs:391:13:391:51 | SSA def(sink67) | LocalDataFlow.cs:392:15:392:20 | access to local variable sink67 | -| LocalDataFlow.cs:391:22:391:51 | call to method Run | LocalDataFlow.cs:391:13:391:51 | SSA def(sink67) | -| LocalDataFlow.cs:391:31:391:50 | [output] (...) => ... | LocalDataFlow.cs:391:22:391:51 | call to method Run | -| LocalDataFlow.cs:392:15:392:20 | [post] access to local variable sink67 | LocalDataFlow.cs:393:28:393:33 | access to local variable sink67 | -| LocalDataFlow.cs:392:15:392:20 | access to local variable sink67 | LocalDataFlow.cs:393:28:393:33 | access to local variable sink67 | -| LocalDataFlow.cs:393:13:393:33 | SSA def(sink68) | LocalDataFlow.cs:394:15:394:20 | access to local variable sink68 | -| LocalDataFlow.cs:393:22:393:33 | await ... | LocalDataFlow.cs:393:13:393:33 | SSA def(sink68) | -| LocalDataFlow.cs:393:28:393:33 | access to local variable sink67 | LocalDataFlow.cs:393:22:393:33 | await ... | -| LocalDataFlow.cs:397:13:397:42 | SSA def(nonSink21) | LocalDataFlow.cs:398:15:398:23 | access to local variable nonSink21 | -| LocalDataFlow.cs:397:25:397:42 | call to method Run | LocalDataFlow.cs:397:13:397:42 | SSA def(nonSink21) | -| LocalDataFlow.cs:397:34:397:41 | [output] (...) => ... | LocalDataFlow.cs:397:25:397:42 | call to method Run | -| LocalDataFlow.cs:398:15:398:23 | [post] access to local variable nonSink21 | LocalDataFlow.cs:399:26:399:34 | access to local variable nonSink21 | -| LocalDataFlow.cs:398:15:398:23 | access to local variable nonSink21 | LocalDataFlow.cs:399:26:399:34 | access to local variable nonSink21 | -| LocalDataFlow.cs:399:9:399:34 | SSA def(nonSink0) | LocalDataFlow.cs:400:15:400:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:399:20:399:34 | await ... | LocalDataFlow.cs:399:9:399:34 | SSA def(nonSink0) | -| LocalDataFlow.cs:399:26:399:34 | access to local variable nonSink21 | LocalDataFlow.cs:399:20:399:34 | await ... | -| LocalDataFlow.cs:400:15:400:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:407:28:407:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:400:15:400:22 | access to local variable nonSink0 | LocalDataFlow.cs:407:28:407:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:403:13:403:36 | SSA def(sink69) | LocalDataFlow.cs:404:15:404:20 | access to local variable sink69 | -| LocalDataFlow.cs:403:22:403:36 | $"..." | LocalDataFlow.cs:403:13:403:36 | SSA def(sink69) | -| LocalDataFlow.cs:407:9:407:37 | SSA def(nonSink0) | LocalDataFlow.cs:408:15:408:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:407:20:407:37 | $"..." | LocalDataFlow.cs:407:9:407:37 | SSA def(nonSink0) | -| LocalDataFlow.cs:408:15:408:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:415:31:415:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:408:15:408:22 | access to local variable nonSink0 | LocalDataFlow.cs:415:31:415:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:411:13:411:34 | SSA def(sink70) | LocalDataFlow.cs:412:15:412:20 | access to local variable sink70 | -| LocalDataFlow.cs:411:22:411:34 | ... = ... | LocalDataFlow.cs:411:13:411:34 | SSA def(sink70) | -| LocalDataFlow.cs:411:22:411:34 | SSA def(sink0) | LocalDataFlow.cs:443:34:443:38 | access to local variable sink0 | -| LocalDataFlow.cs:411:22:411:34 | SSA def(sink0) | LocalDataFlow.cs:444:22:444:26 | access to local variable sink0 | -| LocalDataFlow.cs:411:30:411:34 | access to local variable sink0 | LocalDataFlow.cs:411:22:411:34 | ... = ... | -| LocalDataFlow.cs:411:30:411:34 | access to local variable sink0 | LocalDataFlow.cs:411:22:411:34 | SSA def(sink0) | -| LocalDataFlow.cs:412:15:412:20 | [post] access to local variable sink70 | LocalDataFlow.cs:419:13:419:18 | access to local variable sink70 | -| LocalDataFlow.cs:412:15:412:20 | access to local variable sink70 | LocalDataFlow.cs:419:13:419:18 | access to local variable sink70 | -| LocalDataFlow.cs:415:9:415:38 | SSA def(nonSink0) | LocalDataFlow.cs:416:15:416:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:415:20:415:38 | ... = ... | LocalDataFlow.cs:415:9:415:38 | SSA def(nonSink0) | -| LocalDataFlow.cs:415:31:415:38 | access to local variable nonSink0 | LocalDataFlow.cs:415:20:415:38 | ... = ... | -| LocalDataFlow.cs:416:15:416:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:423:13:423:20 | access to local variable nonSink0 | -| LocalDataFlow.cs:416:15:416:22 | access to local variable nonSink0 | LocalDataFlow.cs:423:13:423:20 | access to local variable nonSink0 | -| LocalDataFlow.cs:419:13:419:18 | access to local variable sink70 | LocalDataFlow.cs:419:23:419:35 | SSA def(sink71) | -| LocalDataFlow.cs:419:13:419:18 | access to local variable sink70 | LocalDataFlow.cs:427:17:427:22 | access to local variable sink70 | -| LocalDataFlow.cs:419:23:419:35 | SSA def(sink71) | LocalDataFlow.cs:420:19:420:24 | access to local variable sink71 | -| LocalDataFlow.cs:423:13:423:20 | access to local variable nonSink0 | LocalDataFlow.cs:423:25:423:40 | SSA def(nonSink16) | -| LocalDataFlow.cs:423:13:423:20 | access to local variable nonSink0 | LocalDataFlow.cs:435:17:435:24 | access to local variable nonSink0 | -| LocalDataFlow.cs:423:25:423:40 | SSA def(nonSink16) | LocalDataFlow.cs:424:19:424:27 | access to local variable nonSink16 | -| LocalDataFlow.cs:427:17:427:22 | access to local variable sink70 | LocalDataFlow.cs:429:18:429:30 | SSA def(sink72) | -| LocalDataFlow.cs:429:18:429:30 | SSA def(sink72) | LocalDataFlow.cs:430:23:430:28 | access to local variable sink72 | -| LocalDataFlow.cs:435:17:435:24 | access to local variable nonSink0 | LocalDataFlow.cs:437:18:437:33 | SSA def(nonSink17) | -| LocalDataFlow.cs:435:17:435:24 | access to local variable nonSink0 | LocalDataFlow.cs:443:22:443:29 | access to local variable nonSink0 | -| LocalDataFlow.cs:437:18:437:33 | SSA def(nonSink17) | LocalDataFlow.cs:438:23:438:31 | access to local variable nonSink17 | -| LocalDataFlow.cs:443:13:443:38 | SSA def(sink73) | LocalDataFlow.cs:445:15:445:20 | access to local variable sink73 | -| LocalDataFlow.cs:443:22:443:29 | access to local variable nonSink0 | LocalDataFlow.cs:443:22:443:38 | ... ?? ... | -| LocalDataFlow.cs:443:22:443:29 | access to local variable nonSink0 | LocalDataFlow.cs:444:31:444:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:443:22:443:38 | ... ?? ... | LocalDataFlow.cs:443:13:443:38 | SSA def(sink73) | -| LocalDataFlow.cs:443:34:443:38 | access to local variable sink0 | LocalDataFlow.cs:443:22:443:38 | ... ?? ... | -| LocalDataFlow.cs:443:34:443:38 | access to local variable sink0 | LocalDataFlow.cs:444:22:444:26 | access to local variable sink0 | -| LocalDataFlow.cs:444:13:444:38 | SSA def(sink74) | LocalDataFlow.cs:446:15:446:20 | access to local variable sink74 | -| LocalDataFlow.cs:444:22:444:26 | access to local variable sink0 | LocalDataFlow.cs:444:22:444:38 | ... ?? ... | -| LocalDataFlow.cs:444:22:444:38 | ... ?? ... | LocalDataFlow.cs:444:13:444:38 | SSA def(sink74) | -| LocalDataFlow.cs:444:31:444:38 | access to local variable nonSink0 | LocalDataFlow.cs:444:22:444:38 | ... ?? ... | -| LocalDataFlow.cs:464:28:464:30 | this | LocalDataFlow.cs:464:41:464:45 | this access | -| LocalDataFlow.cs:464:50:464:52 | this | LocalDataFlow.cs:464:56:464:60 | this access | -| LocalDataFlow.cs:464:50:464:52 | value | LocalDataFlow.cs:464:64:464:68 | access to parameter value | -| LocalDataFlow.cs:470:41:470:47 | tainted | LocalDataFlow.cs:472:15:472:21 | access to parameter tainted | -| LocalDataFlow.cs:475:44:475:53 | nonTainted | LocalDataFlow.cs:477:15:477:24 | access to parameter nonTainted | -| LocalDataFlow.cs:480:44:480:44 | x | LocalDataFlow.cs:483:21:483:21 | access to parameter x | -| LocalDataFlow.cs:480:67:480:68 | os | LocalDataFlow.cs:486:32:486:33 | access to parameter os | -| LocalDataFlow.cs:483:21:483:21 | access to parameter x | LocalDataFlow.cs:483:16:483:21 | ... = ... | -| LocalDataFlow.cs:486:32:486:33 | access to parameter os | LocalDataFlow.cs:486:26:486:33 | ... = ... | -| LocalDataFlow.cs:491:41:491:44 | args | LocalDataFlow.cs:493:29:493:32 | access to parameter args | -| LocalDataFlow.cs:493:29:493:32 | [post] access to parameter args | LocalDataFlow.cs:494:27:494:30 | access to parameter args | -| LocalDataFlow.cs:493:29:493:32 | access to parameter args | LocalDataFlow.cs:494:27:494:30 | access to parameter args | +| LocalDataFlow.cs:66:15:66:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:73:20:73:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:66:15:66:22 | access to local variable nonSink0 | LocalDataFlow.cs:73:20:73:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:69:13:69:32 | SSA def(sink5) | LocalDataFlow.cs:70:15:70:19 | access to local variable sink5 | +| LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | LocalDataFlow.cs:169:33:169:37 | access to local variable sink1 | +| LocalDataFlow.cs:69:21:69:32 | ... + ... | LocalDataFlow.cs:69:13:69:32 | SSA def(sink5) | +| LocalDataFlow.cs:70:15:70:19 | [post] access to local variable sink5 | LocalDataFlow.cs:77:22:77:26 | access to local variable sink5 | +| LocalDataFlow.cs:70:15:70:19 | access to local variable sink5 | LocalDataFlow.cs:77:22:77:26 | access to local variable sink5 | +| LocalDataFlow.cs:73:9:73:36 | SSA def(nonSink0) | LocalDataFlow.cs:74:15:74:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:73:20:73:36 | ... + ... | LocalDataFlow.cs:73:9:73:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:74:15:74:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:81:21:81:28 | access to local variable nonSink0 | +| LocalDataFlow.cs:74:15:74:22 | access to local variable nonSink0 | LocalDataFlow.cs:81:21:81:28 | access to local variable nonSink0 | +| LocalDataFlow.cs:77:13:77:27 | SSA def(sink6) | LocalDataFlow.cs:78:15:78:19 | access to local variable sink6 | +| LocalDataFlow.cs:77:22:77:26 | access to local variable sink5 | LocalDataFlow.cs:77:13:77:27 | SSA def(sink6) | +| LocalDataFlow.cs:78:15:78:19 | [post] access to local variable sink6 | LocalDataFlow.cs:85:31:85:35 | [b (line 49): false] access to local variable sink6 | +| LocalDataFlow.cs:78:15:78:19 | access to local variable sink6 | LocalDataFlow.cs:85:31:85:35 | [b (line 49): false] access to local variable sink6 | +| LocalDataFlow.cs:81:9:81:29 | SSA def(nonSink0) | LocalDataFlow.cs:82:15:82:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:81:21:81:28 | access to local variable nonSink0 | LocalDataFlow.cs:81:9:81:29 | SSA def(nonSink0) | +| LocalDataFlow.cs:85:13:85:35 | [b (line 49): false] SSA def(sink7) | LocalDataFlow.cs:86:15:86:19 | [b (line 49): false] access to local variable sink7 | +| LocalDataFlow.cs:85:13:85:35 | [b (line 49): true] SSA def(sink7) | LocalDataFlow.cs:86:15:86:19 | [b (line 49): true] access to local variable sink7 | +| LocalDataFlow.cs:85:21:85:21 | access to parameter b | LocalDataFlow.cs:89:20:89:20 | [b (line 49): false] access to parameter b | +| LocalDataFlow.cs:85:21:85:21 | access to parameter b | LocalDataFlow.cs:89:20:89:20 | [b (line 49): true] access to parameter b | +| LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | LocalDataFlow.cs:85:13:85:35 | [b (line 49): false] SSA def(sink7) | +| LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | LocalDataFlow.cs:85:13:85:35 | [b (line 49): true] SSA def(sink7) | +| LocalDataFlow.cs:85:25:85:27 | [b (line 49): true] "a" | LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | +| LocalDataFlow.cs:85:31:85:35 | [b (line 49): false] access to local variable sink6 | LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | +| LocalDataFlow.cs:86:15:86:19 | [b (line 49): false] access to local variable sink7 | LocalDataFlow.cs:89:9:89:36 | SSA phi(sink7) | +| LocalDataFlow.cs:86:15:86:19 | [b (line 49): true] access to local variable sink7 | LocalDataFlow.cs:89:9:89:36 | SSA phi(sink7) | +| LocalDataFlow.cs:89:9:89:36 | SSA def(nonSink0) | LocalDataFlow.cs:90:15:90:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:89:9:89:36 | SSA phi(sink7) | LocalDataFlow.cs:93:29:93:33 | access to local variable sink7 | +| LocalDataFlow.cs:89:20:89:36 | [b (line 49): false] ... ? ... : ... | LocalDataFlow.cs:89:9:89:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:89:20:89:36 | [b (line 49): true] ... ? ... : ... | LocalDataFlow.cs:89:9:89:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:89:24:89:28 | "abc" | LocalDataFlow.cs:89:20:89:36 | [b (line 49): true] ... ? ... : ... | +| LocalDataFlow.cs:89:32:89:36 | "def" | LocalDataFlow.cs:89:20:89:36 | [b (line 49): false] ... ? ... : ... | +| LocalDataFlow.cs:90:15:90:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:90:15:90:22 | access to local variable nonSink0 | LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:93:13:93:33 | SSA def(sink8) | LocalDataFlow.cs:94:15:94:19 | access to local variable sink8 | +| LocalDataFlow.cs:93:21:93:33 | (...) ... | LocalDataFlow.cs:93:13:93:33 | SSA def(sink8) | +| LocalDataFlow.cs:93:29:93:33 | access to local variable sink7 | LocalDataFlow.cs:93:21:93:33 | (...) ... | +| LocalDataFlow.cs:94:15:94:19 | [post] access to local variable sink8 | LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | +| LocalDataFlow.cs:94:15:94:19 | access to local variable sink8 | LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | +| LocalDataFlow.cs:97:13:97:39 | SSA def(nonSink3) | LocalDataFlow.cs:98:15:98:22 | access to local variable nonSink3 | +| LocalDataFlow.cs:97:24:97:39 | (...) ... | LocalDataFlow.cs:97:13:97:39 | SSA def(nonSink3) | +| LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | LocalDataFlow.cs:97:24:97:39 | (...) ... | +| LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | LocalDataFlow.cs:105:20:105:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:101:13:101:35 | SSA def(sink9) | LocalDataFlow.cs:102:15:102:19 | access to local variable sink9 | +| LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | LocalDataFlow.cs:101:21:101:35 | ... as ... | +| LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | LocalDataFlow.cs:165:22:165:26 | access to local variable sink8 | +| LocalDataFlow.cs:101:21:101:35 | ... as ... | LocalDataFlow.cs:101:13:101:35 | SSA def(sink9) | +| LocalDataFlow.cs:102:15:102:19 | [post] access to local variable sink9 | LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | +| LocalDataFlow.cs:102:15:102:19 | access to local variable sink9 | LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | +| LocalDataFlow.cs:105:9:105:37 | SSA def(nonSink3) | LocalDataFlow.cs:106:15:106:22 | access to local variable nonSink3 | +| LocalDataFlow.cs:105:20:105:27 | access to local variable nonSink0 | LocalDataFlow.cs:105:20:105:37 | ... as ... | +| LocalDataFlow.cs:105:20:105:27 | access to local variable nonSink0 | LocalDataFlow.cs:114:22:114:29 | access to local variable nonSink0 | +| LocalDataFlow.cs:105:20:105:37 | ... as ... | LocalDataFlow.cs:105:9:105:37 | SSA def(nonSink3) | +| LocalDataFlow.cs:106:15:106:22 | [post] access to local variable nonSink3 | LocalDataFlow.cs:171:33:171:40 | access to local variable nonSink3 | +| LocalDataFlow.cs:106:15:106:22 | access to local variable nonSink3 | LocalDataFlow.cs:171:33:171:40 | access to local variable nonSink3 | +| LocalDataFlow.cs:109:13:109:39 | SSA def(sink15) | LocalDataFlow.cs:110:15:110:20 | access to local variable sink15 | +| LocalDataFlow.cs:109:22:109:39 | call to method Parse | LocalDataFlow.cs:109:13:109:39 | SSA def(sink15) | +| LocalDataFlow.cs:109:34:109:38 | [post] access to local variable sink9 | LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | +| LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | +| LocalDataFlow.cs:110:15:110:20 | access to local variable sink15 | LocalDataFlow.cs:161:22:161:27 | access to local variable sink15 | +| LocalDataFlow.cs:112:13:112:56 | SSA def(sink16) | LocalDataFlow.cs:113:15:113:20 | access to local variable sink16 | +| LocalDataFlow.cs:112:22:112:56 | call to method TryParse | LocalDataFlow.cs:112:13:112:56 | SSA def(sink16) | +| LocalDataFlow.cs:112:37:112:41 | [post] access to local variable sink9 | LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | +| LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | +| LocalDataFlow.cs:114:13:114:49 | SSA def(sink17) | LocalDataFlow.cs:115:15:115:20 | access to local variable sink17 | +| LocalDataFlow.cs:114:22:114:29 | [post] access to local variable nonSink0 | LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | +| LocalDataFlow.cs:114:22:114:29 | access to local variable nonSink0 | LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | +| LocalDataFlow.cs:114:22:114:49 | call to method Replace | LocalDataFlow.cs:114:13:114:49 | SSA def(sink17) | +| LocalDataFlow.cs:114:44:114:48 | [post] access to local variable sink9 | LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | +| LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | +| LocalDataFlow.cs:116:13:116:51 | SSA def(sink18) | LocalDataFlow.cs:117:15:117:20 | access to local variable sink18 | +| LocalDataFlow.cs:116:22:116:51 | call to method Format | LocalDataFlow.cs:116:13:116:51 | SSA def(sink18) | +| LocalDataFlow.cs:116:36:116:43 | [post] access to local variable nonSink0 | LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:116:46:116:50 | [post] access to local variable sink9 | LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | +| LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | +| LocalDataFlow.cs:117:15:117:20 | [post] access to local variable sink18 | LocalDataFlow.cs:118:36:118:41 | access to local variable sink18 | +| LocalDataFlow.cs:117:15:117:20 | access to local variable sink18 | LocalDataFlow.cs:118:36:118:41 | access to local variable sink18 | +| LocalDataFlow.cs:118:13:118:52 | SSA def(sink19) | LocalDataFlow.cs:119:15:119:20 | access to local variable sink19 | +| LocalDataFlow.cs:118:22:118:52 | call to method Format | LocalDataFlow.cs:118:13:118:52 | SSA def(sink19) | +| LocalDataFlow.cs:118:44:118:51 | [post] access to local variable nonSink0 | LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:120:13:120:38 | SSA def(sink45) | LocalDataFlow.cs:121:15:121:20 | access to local variable sink45 | +| LocalDataFlow.cs:120:22:120:38 | call to method Parse | LocalDataFlow.cs:120:13:120:38 | SSA def(sink45) | +| LocalDataFlow.cs:120:33:120:37 | [post] access to local variable sink9 | LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | +| LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | +| LocalDataFlow.cs:123:13:123:56 | SSA def(sink46) | LocalDataFlow.cs:124:15:124:20 | access to local variable sink46 | +| LocalDataFlow.cs:123:22:123:56 | call to method TryParse | LocalDataFlow.cs:123:13:123:56 | SSA def(sink46) | +| LocalDataFlow.cs:123:36:123:40 | [post] access to local variable sink9 | LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | +| LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | +| LocalDataFlow.cs:124:15:124:20 | access to local variable sink46 | LocalDataFlow.cs:125:37:125:42 | access to local variable sink46 | +| LocalDataFlow.cs:125:13:125:43 | SSA def(sink47) | LocalDataFlow.cs:126:15:126:20 | access to local variable sink47 | +| LocalDataFlow.cs:125:22:125:43 | call to method ToByte | LocalDataFlow.cs:125:13:125:43 | SSA def(sink47) | +| LocalDataFlow.cs:126:15:126:20 | access to local variable sink47 | LocalDataFlow.cs:127:40:127:45 | access to local variable sink47 | +| LocalDataFlow.cs:127:13:127:46 | SSA def(sink49) | LocalDataFlow.cs:128:15:128:20 | access to local variable sink49 | +| LocalDataFlow.cs:127:22:127:46 | call to method Concat | LocalDataFlow.cs:127:13:127:46 | SSA def(sink49) | +| LocalDataFlow.cs:127:40:127:45 | access to local variable sink47 | LocalDataFlow.cs:127:40:127:45 | (...) ... | +| LocalDataFlow.cs:128:15:128:20 | [post] access to local variable sink49 | LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | +| LocalDataFlow.cs:128:15:128:20 | access to local variable sink49 | LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | +| LocalDataFlow.cs:129:13:129:40 | SSA def(sink50) | LocalDataFlow.cs:130:15:130:20 | access to local variable sink50 | +| LocalDataFlow.cs:129:22:129:40 | call to method Copy | LocalDataFlow.cs:129:13:129:40 | SSA def(sink50) | +| LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | LocalDataFlow.cs:129:22:129:40 | call to method Copy | +| LocalDataFlow.cs:130:15:130:20 | [post] access to local variable sink50 | LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | +| LocalDataFlow.cs:130:15:130:20 | access to local variable sink50 | LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | +| LocalDataFlow.cs:131:13:131:54 | SSA def(sink51) | LocalDataFlow.cs:132:15:132:20 | access to local variable sink51 | +| LocalDataFlow.cs:131:22:131:54 | call to method Join | LocalDataFlow.cs:131:13:131:54 | SSA def(sink51) | +| LocalDataFlow.cs:132:15:132:20 | [post] access to local variable sink51 | LocalDataFlow.cs:133:35:133:40 | access to local variable sink51 | +| LocalDataFlow.cs:132:15:132:20 | access to local variable sink51 | LocalDataFlow.cs:133:35:133:40 | access to local variable sink51 | +| LocalDataFlow.cs:133:13:133:41 | SSA def(sink52) | LocalDataFlow.cs:134:15:134:20 | access to local variable sink52 | +| LocalDataFlow.cs:133:22:133:41 | call to method Insert | LocalDataFlow.cs:133:13:133:41 | SSA def(sink52) | +| LocalDataFlow.cs:137:9:137:40 | SSA def(nonSink2) | LocalDataFlow.cs:138:15:138:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:137:20:137:40 | call to method Parse | LocalDataFlow.cs:137:9:137:40 | SSA def(nonSink2) | +| LocalDataFlow.cs:137:32:137:39 | [post] access to local variable nonSink0 | LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:139:13:139:61 | SSA def(nonSink7) | LocalDataFlow.cs:140:15:140:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:139:24:139:61 | call to method TryParse | LocalDataFlow.cs:139:13:139:61 | SSA def(nonSink7) | +| LocalDataFlow.cs:139:39:139:46 | [post] access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:141:9:141:50 | SSA def(nonSink0) | LocalDataFlow.cs:142:15:142:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:141:20:141:27 | [post] access to local variable nonSink0 | LocalDataFlow.cs:141:42:141:49 | access to local variable nonSink0 | +| LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | LocalDataFlow.cs:141:42:141:49 | access to local variable nonSink0 | +| LocalDataFlow.cs:141:20:141:50 | call to method Replace | LocalDataFlow.cs:141:9:141:50 | SSA def(nonSink0) | +| LocalDataFlow.cs:142:15:142:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:142:15:142:22 | access to local variable nonSink0 | LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:143:9:143:52 | SSA def(nonSink0) | LocalDataFlow.cs:144:15:144:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:143:20:143:52 | call to method Format | LocalDataFlow.cs:143:9:143:52 | SSA def(nonSink0) | +| LocalDataFlow.cs:143:34:143:41 | [post] access to local variable nonSink0 | LocalDataFlow.cs:143:44:143:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | LocalDataFlow.cs:143:44:143:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:144:15:144:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:144:15:144:22 | access to local variable nonSink0 | LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:145:9:145:39 | SSA def(nonSink7) | LocalDataFlow.cs:146:15:146:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:145:20:145:39 | call to method Parse | LocalDataFlow.cs:145:9:145:39 | SSA def(nonSink7) | +| LocalDataFlow.cs:145:31:145:38 | [post] access to local variable nonSink0 | LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:147:9:147:57 | SSA def(nonSink7) | LocalDataFlow.cs:148:15:148:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:147:20:147:57 | call to method TryParse | LocalDataFlow.cs:147:9:147:57 | SSA def(nonSink7) | +| LocalDataFlow.cs:148:15:148:22 | access to local variable nonSink7 | LocalDataFlow.cs:149:40:149:47 | access to local variable nonSink7 | +| LocalDataFlow.cs:149:13:149:48 | SSA def(nonSink14) | LocalDataFlow.cs:150:15:150:23 | access to local variable nonSink14 | +| LocalDataFlow.cs:149:25:149:48 | call to method ToByte | LocalDataFlow.cs:149:13:149:48 | SSA def(nonSink14) | +| LocalDataFlow.cs:149:40:149:47 | access to local variable nonSink7 | LocalDataFlow.cs:151:38:151:45 | access to local variable nonSink7 | +| LocalDataFlow.cs:151:9:151:46 | SSA def(nonSink0) | LocalDataFlow.cs:152:15:152:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:151:20:151:46 | call to method Concat | LocalDataFlow.cs:151:9:151:46 | SSA def(nonSink0) | +| LocalDataFlow.cs:151:38:151:45 | access to local variable nonSink7 | LocalDataFlow.cs:151:38:151:45 | (...) ... | +| LocalDataFlow.cs:152:15:152:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:152:15:152:22 | access to local variable nonSink0 | LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:153:9:153:40 | SSA def(nonSink0) | LocalDataFlow.cs:154:15:154:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:153:20:153:40 | call to method Copy | LocalDataFlow.cs:153:9:153:40 | SSA def(nonSink0) | +| LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | LocalDataFlow.cs:153:20:153:40 | call to method Copy | +| LocalDataFlow.cs:154:15:154:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | +| LocalDataFlow.cs:154:15:154:22 | access to local variable nonSink0 | LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | +| LocalDataFlow.cs:155:9:155:54 | SSA def(nonSink0) | LocalDataFlow.cs:156:15:156:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:155:20:155:54 | call to method Join | LocalDataFlow.cs:155:9:155:54 | SSA def(nonSink0) | +| LocalDataFlow.cs:156:15:156:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:157:33:157:40 | access to local variable nonSink0 | +| LocalDataFlow.cs:156:15:156:22 | access to local variable nonSink0 | LocalDataFlow.cs:157:33:157:40 | access to local variable nonSink0 | +| LocalDataFlow.cs:157:9:157:41 | SSA def(nonSink0) | LocalDataFlow.cs:158:15:158:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:157:20:157:41 | call to method Insert | LocalDataFlow.cs:157:9:157:41 | SSA def(nonSink0) | +| LocalDataFlow.cs:158:15:158:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:195:39:195:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:158:15:158:22 | access to local variable nonSink0 | LocalDataFlow.cs:195:39:195:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:161:13:161:32 | SSA def(sink20) | LocalDataFlow.cs:162:15:162:20 | access to local variable sink20 | +| LocalDataFlow.cs:161:22:161:32 | ... > ... | LocalDataFlow.cs:161:13:161:32 | SSA def(sink20) | +| LocalDataFlow.cs:162:15:162:20 | access to local variable sink20 | LocalDataFlow.cs:175:22:175:27 | access to local variable sink20 | +| LocalDataFlow.cs:163:13:163:40 | SSA def(sink21) | LocalDataFlow.cs:164:15:164:20 | access to local variable sink21 | +| LocalDataFlow.cs:163:22:163:26 | [post] access to local variable sink9 | LocalDataFlow.cs:183:37:183:41 | access to local variable sink9 | +| LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | LocalDataFlow.cs:183:37:183:41 | access to local variable sink9 | +| LocalDataFlow.cs:163:22:163:40 | call to method Equals | LocalDataFlow.cs:163:13:163:40 | SSA def(sink21) | +| LocalDataFlow.cs:165:13:165:45 | SSA def(sink22) | LocalDataFlow.cs:166:15:166:20 | access to local variable sink22 | +| LocalDataFlow.cs:165:22:165:26 | [post] access to local variable sink8 | LocalDataFlow.cs:171:20:171:24 | access to local variable sink8 | +| LocalDataFlow.cs:165:22:165:26 | access to local variable sink8 | LocalDataFlow.cs:171:20:171:24 | access to local variable sink8 | +| LocalDataFlow.cs:165:22:165:45 | call to method Equals | LocalDataFlow.cs:165:13:165:45 | SSA def(sink22) | +| LocalDataFlow.cs:165:43:165:44 | 41 | LocalDataFlow.cs:165:35:165:44 | (...) ... | +| LocalDataFlow.cs:169:9:169:38 | SSA def(nonSink7) | LocalDataFlow.cs:170:15:170:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:169:20:169:24 | [post] access to local variable sink0 | LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | +| LocalDataFlow.cs:169:20:169:24 | access to local variable sink0 | LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | +| LocalDataFlow.cs:169:20:169:38 | call to method Equals | LocalDataFlow.cs:169:9:169:38 | SSA def(nonSink7) | +| LocalDataFlow.cs:169:33:169:37 | [post] access to local variable sink1 | LocalDataFlow.cs:286:30:286:34 | access to local variable sink1 | +| LocalDataFlow.cs:169:33:169:37 | access to local variable sink1 | LocalDataFlow.cs:286:30:286:34 | access to local variable sink1 | +| LocalDataFlow.cs:171:9:171:41 | SSA def(nonSink7) | LocalDataFlow.cs:172:15:172:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:171:20:171:41 | call to method Equals | LocalDataFlow.cs:171:9:171:41 | SSA def(nonSink7) | +| LocalDataFlow.cs:172:15:172:22 | access to local variable nonSink7 | LocalDataFlow.cs:179:20:179:27 | access to local variable nonSink7 | +| LocalDataFlow.cs:175:13:175:36 | SSA def(sink25) | LocalDataFlow.cs:176:15:176:20 | access to local variable sink25 | +| LocalDataFlow.cs:175:22:175:36 | ... \|\| ... | LocalDataFlow.cs:175:13:175:36 | SSA def(sink25) | +| LocalDataFlow.cs:179:9:179:36 | SSA def(nonSink7) | LocalDataFlow.cs:180:15:180:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:179:20:179:36 | ... \|\| ... | LocalDataFlow.cs:179:9:179:36 | SSA def(nonSink7) | +| LocalDataFlow.cs:183:13:183:42 | SSA def(sink26) | LocalDataFlow.cs:184:15:184:20 | access to local variable sink26 | +| LocalDataFlow.cs:183:22:183:42 | object creation of type Uri | LocalDataFlow.cs:183:13:183:42 | SSA def(sink26) | +| LocalDataFlow.cs:184:15:184:20 | [post] access to local variable sink26 | LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | +| LocalDataFlow.cs:184:15:184:20 | access to local variable sink26 | LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | +| LocalDataFlow.cs:185:13:185:38 | SSA def(sink27) | LocalDataFlow.cs:186:15:186:20 | access to local variable sink27 | +| LocalDataFlow.cs:185:22:185:27 | [post] access to local variable sink26 | LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | +| LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | +| LocalDataFlow.cs:185:22:185:38 | call to method ToString | LocalDataFlow.cs:185:13:185:38 | SSA def(sink27) | +| LocalDataFlow.cs:187:13:187:40 | SSA def(sink28) | LocalDataFlow.cs:188:15:188:20 | access to local variable sink28 | +| LocalDataFlow.cs:187:22:187:27 | [post] access to local variable sink26 | LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | +| LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | +| LocalDataFlow.cs:187:22:187:40 | access to property PathAndQuery | LocalDataFlow.cs:187:13:187:40 | SSA def(sink28) | +| LocalDataFlow.cs:189:13:189:33 | SSA def(sink29) | LocalDataFlow.cs:190:15:190:20 | access to local variable sink29 | +| LocalDataFlow.cs:189:22:189:27 | [post] access to local variable sink26 | LocalDataFlow.cs:191:22:191:27 | access to local variable sink26 | +| LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | LocalDataFlow.cs:191:22:191:27 | access to local variable sink26 | +| LocalDataFlow.cs:189:22:189:33 | access to property Query | LocalDataFlow.cs:189:13:189:33 | SSA def(sink29) | +| LocalDataFlow.cs:191:13:191:42 | SSA def(sink30) | LocalDataFlow.cs:192:15:192:20 | access to local variable sink30 | +| LocalDataFlow.cs:191:22:191:42 | access to property OriginalString | LocalDataFlow.cs:191:13:191:42 | SSA def(sink30) | +| LocalDataFlow.cs:192:15:192:20 | [post] access to local variable sink30 | LocalDataFlow.cs:207:49:207:54 | access to local variable sink30 | +| LocalDataFlow.cs:192:15:192:20 | access to local variable sink30 | LocalDataFlow.cs:207:49:207:54 | access to local variable sink30 | +| LocalDataFlow.cs:195:13:195:47 | SSA def(nonSink8) | LocalDataFlow.cs:196:15:196:22 | access to local variable nonSink8 | +| LocalDataFlow.cs:195:24:195:47 | object creation of type Uri | LocalDataFlow.cs:195:13:195:47 | SSA def(nonSink8) | +| LocalDataFlow.cs:196:15:196:22 | [post] access to local variable nonSink8 | LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:196:15:196:22 | access to local variable nonSink8 | LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:197:9:197:38 | SSA def(nonSink0) | LocalDataFlow.cs:198:15:198:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:197:20:197:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:197:20:197:38 | call to method ToString | LocalDataFlow.cs:197:9:197:38 | SSA def(nonSink0) | +| LocalDataFlow.cs:199:9:199:40 | SSA def(nonSink0) | LocalDataFlow.cs:200:15:200:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:199:20:199:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:199:20:199:40 | access to property PathAndQuery | LocalDataFlow.cs:199:9:199:40 | SSA def(nonSink0) | +| LocalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) | LocalDataFlow.cs:202:15:202:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:201:20:201:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:203:20:203:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | LocalDataFlow.cs:203:20:203:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:201:20:201:33 | access to property Query | LocalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) | +| LocalDataFlow.cs:203:9:203:42 | SSA def(nonSink0) | LocalDataFlow.cs:204:15:204:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:203:20:203:42 | access to property OriginalString | LocalDataFlow.cs:203:9:203:42 | SSA def(nonSink0) | +| LocalDataFlow.cs:204:15:204:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:213:51:213:58 | access to local variable nonSink0 | +| LocalDataFlow.cs:204:15:204:22 | access to local variable nonSink0 | LocalDataFlow.cs:213:51:213:58 | access to local variable nonSink0 | +| LocalDataFlow.cs:207:13:207:55 | SSA def(sink31) | LocalDataFlow.cs:208:15:208:20 | access to local variable sink31 | +| LocalDataFlow.cs:207:22:207:55 | object creation of type StringReader | LocalDataFlow.cs:207:13:207:55 | SSA def(sink31) | +| LocalDataFlow.cs:208:15:208:20 | [post] access to local variable sink31 | LocalDataFlow.cs:209:22:209:27 | access to local variable sink31 | +| LocalDataFlow.cs:208:15:208:20 | access to local variable sink31 | LocalDataFlow.cs:209:22:209:27 | access to local variable sink31 | +| LocalDataFlow.cs:209:13:209:39 | SSA def(sink32) | LocalDataFlow.cs:210:15:210:20 | access to local variable sink32 | +| LocalDataFlow.cs:209:22:209:39 | call to method ReadToEnd | LocalDataFlow.cs:209:13:209:39 | SSA def(sink32) | +| LocalDataFlow.cs:210:15:210:20 | [post] access to local variable sink32 | LocalDataFlow.cs:219:30:219:35 | access to local variable sink32 | +| LocalDataFlow.cs:210:15:210:20 | access to local variable sink32 | LocalDataFlow.cs:219:30:219:35 | access to local variable sink32 | +| LocalDataFlow.cs:213:13:213:59 | SSA def(nonSink9) | LocalDataFlow.cs:214:15:214:22 | access to local variable nonSink9 | +| LocalDataFlow.cs:213:24:213:59 | object creation of type StringReader | LocalDataFlow.cs:213:13:213:59 | SSA def(nonSink9) | +| LocalDataFlow.cs:214:15:214:22 | [post] access to local variable nonSink9 | LocalDataFlow.cs:215:20:215:27 | access to local variable nonSink9 | +| LocalDataFlow.cs:214:15:214:22 | access to local variable nonSink9 | LocalDataFlow.cs:215:20:215:27 | access to local variable nonSink9 | +| LocalDataFlow.cs:215:9:215:39 | SSA def(nonSink0) | LocalDataFlow.cs:216:15:216:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:215:20:215:39 | call to method ReadToEnd | LocalDataFlow.cs:215:9:215:39 | SSA def(nonSink0) | +| LocalDataFlow.cs:216:15:216:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:225:28:225:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:216:15:216:22 | access to local variable nonSink0 | LocalDataFlow.cs:225:28:225:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:219:13:219:127 | SSA def(sink33) | LocalDataFlow.cs:220:15:220:20 | access to local variable sink33 | +| LocalDataFlow.cs:219:22:219:127 | (...) ... | LocalDataFlow.cs:219:13:219:127 | SSA def(sink33) | +| LocalDataFlow.cs:219:30:219:119 | call to method Insert | LocalDataFlow.cs:219:30:219:127 | call to method Clone | +| LocalDataFlow.cs:219:30:219:127 | call to method Clone | LocalDataFlow.cs:219:22:219:127 | (...) ... | +| LocalDataFlow.cs:220:15:220:20 | [post] access to local variable sink33 | LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | +| LocalDataFlow.cs:220:15:220:20 | access to local variable sink33 | LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | +| LocalDataFlow.cs:221:13:221:63 | SSA def(sink48) | LocalDataFlow.cs:222:15:222:20 | access to local variable sink48 | +| LocalDataFlow.cs:221:22:221:27 | [post] access to local variable sink33 | LocalDataFlow.cs:231:40:231:45 | access to local variable sink33 | +| LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | LocalDataFlow.cs:231:40:231:45 | access to local variable sink33 | +| LocalDataFlow.cs:221:22:221:63 | call to method Split | LocalDataFlow.cs:221:13:221:63 | SSA def(sink48) | +| LocalDataFlow.cs:225:9:225:127 | SSA def(nonSink0) | LocalDataFlow.cs:226:15:226:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:225:20:225:127 | (...) ... | LocalDataFlow.cs:225:9:225:127 | SSA def(nonSink0) | +| LocalDataFlow.cs:225:28:225:119 | call to method Insert | LocalDataFlow.cs:225:28:225:127 | call to method Clone | +| LocalDataFlow.cs:225:28:225:127 | call to method Clone | LocalDataFlow.cs:225:20:225:127 | (...) ... | +| LocalDataFlow.cs:226:15:226:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | +| LocalDataFlow.cs:226:15:226:22 | access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | +| LocalDataFlow.cs:227:13:227:68 | SSA def(nonSink15) | LocalDataFlow.cs:228:15:228:23 | access to local variable nonSink15 | +| LocalDataFlow.cs:227:25:227:32 | [post] access to local variable nonSink0 | LocalDataFlow.cs:240:43:240:50 | access to local variable nonSink0 | +| LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | LocalDataFlow.cs:240:43:240:50 | access to local variable nonSink0 | +| LocalDataFlow.cs:227:25:227:68 | call to method Split | LocalDataFlow.cs:227:13:227:68 | SSA def(nonSink15) | +| LocalDataFlow.cs:231:13:231:46 | SSA def(sink34) | LocalDataFlow.cs:232:15:232:20 | access to local variable sink34 | +| LocalDataFlow.cs:231:22:231:46 | object creation of type StringBuilder | LocalDataFlow.cs:231:13:231:46 | SSA def(sink34) | +| LocalDataFlow.cs:232:15:232:20 | [post] access to local variable sink34 | LocalDataFlow.cs:233:22:233:27 | access to local variable sink34 | +| LocalDataFlow.cs:232:15:232:20 | access to local variable sink34 | LocalDataFlow.cs:233:22:233:27 | access to local variable sink34 | +| LocalDataFlow.cs:233:13:233:38 | SSA def(sink35) | LocalDataFlow.cs:234:15:234:20 | access to local variable sink35 | +| LocalDataFlow.cs:233:22:233:38 | call to method ToString | LocalDataFlow.cs:233:13:233:38 | SSA def(sink35) | +| LocalDataFlow.cs:234:15:234:20 | [post] access to local variable sink35 | LocalDataFlow.cs:236:27:236:32 | access to local variable sink35 | +| LocalDataFlow.cs:234:15:234:20 | access to local variable sink35 | LocalDataFlow.cs:236:27:236:32 | access to local variable sink35 | +| LocalDataFlow.cs:235:13:235:42 | SSA def(sink36) | LocalDataFlow.cs:236:9:236:14 | access to local variable sink36 | +| LocalDataFlow.cs:235:22:235:42 | object creation of type StringBuilder | LocalDataFlow.cs:235:13:235:42 | SSA def(sink36) | +| LocalDataFlow.cs:236:9:236:14 | [post] access to local variable sink36 | LocalDataFlow.cs:237:15:237:20 | access to local variable sink36 | +| LocalDataFlow.cs:236:9:236:14 | access to local variable sink36 | LocalDataFlow.cs:237:15:237:20 | access to local variable sink36 | +| LocalDataFlow.cs:240:13:240:51 | SSA def(nonSink10) | LocalDataFlow.cs:241:15:241:23 | access to local variable nonSink10 | +| LocalDataFlow.cs:240:25:240:51 | object creation of type StringBuilder | LocalDataFlow.cs:240:13:240:51 | SSA def(nonSink10) | +| LocalDataFlow.cs:241:15:241:23 | [post] access to local variable nonSink10 | LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | +| LocalDataFlow.cs:241:15:241:23 | access to local variable nonSink10 | LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | +| LocalDataFlow.cs:242:9:242:39 | SSA def(nonSink0) | LocalDataFlow.cs:243:15:243:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:242:20:242:28 | [post] access to local variable nonSink10 | LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | +| LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | +| LocalDataFlow.cs:242:20:242:39 | call to method ToString | LocalDataFlow.cs:242:9:242:39 | SSA def(nonSink0) | +| LocalDataFlow.cs:243:15:243:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:244:30:244:37 | access to local variable nonSink0 | +| LocalDataFlow.cs:243:15:243:22 | access to local variable nonSink0 | LocalDataFlow.cs:244:30:244:37 | access to local variable nonSink0 | +| LocalDataFlow.cs:244:9:244:17 | [post] access to local variable nonSink10 | LocalDataFlow.cs:245:15:245:23 | access to local variable nonSink10 | +| LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | LocalDataFlow.cs:245:15:245:23 | access to local variable nonSink10 | +| LocalDataFlow.cs:248:13:248:52 | SSA def(taintedDataContract) | LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:248:13:248:52 | SSA qualifier def(taintedDataContract.AList) | LocalDataFlow.cs:251:22:251:46 | access to property AList | +| LocalDataFlow.cs:248:35:248:52 | object creation of type DataContract | LocalDataFlow.cs:248:13:248:52 | SSA def(taintedDataContract) | +| LocalDataFlow.cs:249:13:249:48 | SSA def(sink53) | LocalDataFlow.cs:250:15:250:20 | access to local variable sink53 | +| LocalDataFlow.cs:249:22:249:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:249:22:249:48 | access to property AString | LocalDataFlow.cs:249:13:249:48 | SSA def(sink53) | +| LocalDataFlow.cs:251:13:251:57 | SSA def(sink54) | LocalDataFlow.cs:252:15:252:20 | access to local variable sink54 | +| LocalDataFlow.cs:251:22:251:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:251:22:251:46 | [post] access to property AList | LocalDataFlow.cs:260:20:260:44 | access to property AList | +| LocalDataFlow.cs:251:22:251:46 | access to property AList | LocalDataFlow.cs:260:20:260:44 | access to property AList | +| LocalDataFlow.cs:251:22:251:57 | access to property AString | LocalDataFlow.cs:251:13:251:57 | SSA def(sink54) | +| LocalDataFlow.cs:255:13:255:55 | SSA def(nonTaintedDataContract) | LocalDataFlow.cs:256:20:256:41 | access to local variable nonTaintedDataContract | +| LocalDataFlow.cs:255:38:255:55 | object creation of type DataContract | LocalDataFlow.cs:255:13:255:55 | SSA def(nonTaintedDataContract) | +| LocalDataFlow.cs:256:9:256:49 | SSA def(nonSink0) | LocalDataFlow.cs:257:15:257:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:256:20:256:49 | access to property AString | LocalDataFlow.cs:256:9:256:49 | SSA def(nonSink0) | +| LocalDataFlow.cs:258:9:258:44 | SSA def(nonSink2) | LocalDataFlow.cs:259:15:259:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:258:20:258:38 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:258:20:258:44 | access to property AnInt | LocalDataFlow.cs:258:9:258:44 | SSA def(nonSink2) | +| LocalDataFlow.cs:260:9:260:53 | SSA def(nonSink2) | LocalDataFlow.cs:261:15:261:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:260:20:260:53 | access to property AnInt | LocalDataFlow.cs:260:9:260:53 | SSA def(nonSink2) | +| LocalDataFlow.cs:264:17:264:37 | SSA def(taintedTextBox) | LocalDataFlow.cs:265:22:265:35 | access to local variable taintedTextBox | +| LocalDataFlow.cs:264:34:264:37 | null | LocalDataFlow.cs:264:17:264:37 | SSA def(taintedTextBox) | +| LocalDataFlow.cs:265:13:265:40 | SSA def(sink60) | LocalDataFlow.cs:266:15:266:20 | access to local variable sink60 | +| LocalDataFlow.cs:265:22:265:40 | access to property Text | LocalDataFlow.cs:265:13:265:40 | SSA def(sink60) | +| LocalDataFlow.cs:269:17:269:40 | SSA def(nonTaintedTextBox) | LocalDataFlow.cs:270:20:270:36 | access to local variable nonTaintedTextBox | +| LocalDataFlow.cs:269:37:269:40 | null | LocalDataFlow.cs:269:17:269:40 | SSA def(nonTaintedTextBox) | +| LocalDataFlow.cs:270:9:270:41 | SSA def(nonSink0) | LocalDataFlow.cs:271:15:271:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:270:20:270:41 | access to property Text | LocalDataFlow.cs:270:9:270:41 | SSA def(nonSink0) | +| LocalDataFlow.cs:274:13:274:51 | SSA def(sink67) | LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | +| LocalDataFlow.cs:274:22:274:51 | call to method Run | LocalDataFlow.cs:274:13:274:51 | SSA def(sink67) | +| LocalDataFlow.cs:274:31:274:50 | [output] (...) => ... | LocalDataFlow.cs:274:22:274:51 | call to method Run | +| LocalDataFlow.cs:275:15:275:20 | [post] access to local variable sink67 | LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | +| LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | +| LocalDataFlow.cs:276:13:276:33 | SSA def(sink68) | LocalDataFlow.cs:277:15:277:20 | access to local variable sink68 | +| LocalDataFlow.cs:276:22:276:33 | await ... | LocalDataFlow.cs:276:13:276:33 | SSA def(sink68) | +| LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | LocalDataFlow.cs:276:22:276:33 | await ... | +| LocalDataFlow.cs:280:13:280:42 | SSA def(nonSink21) | LocalDataFlow.cs:281:15:281:23 | access to local variable nonSink21 | +| LocalDataFlow.cs:280:25:280:42 | call to method Run | LocalDataFlow.cs:280:13:280:42 | SSA def(nonSink21) | +| LocalDataFlow.cs:280:34:280:41 | [output] (...) => ... | LocalDataFlow.cs:280:25:280:42 | call to method Run | +| LocalDataFlow.cs:281:15:281:23 | [post] access to local variable nonSink21 | LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | +| LocalDataFlow.cs:281:15:281:23 | access to local variable nonSink21 | LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | +| LocalDataFlow.cs:282:9:282:34 | SSA def(nonSink0) | LocalDataFlow.cs:283:15:283:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:282:20:282:34 | await ... | LocalDataFlow.cs:282:9:282:34 | SSA def(nonSink0) | +| LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | LocalDataFlow.cs:282:20:282:34 | await ... | +| LocalDataFlow.cs:283:15:283:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:290:28:290:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:283:15:283:22 | access to local variable nonSink0 | LocalDataFlow.cs:290:28:290:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:286:13:286:36 | SSA def(sink69) | LocalDataFlow.cs:287:15:287:20 | access to local variable sink69 | +| LocalDataFlow.cs:286:22:286:36 | $"..." | LocalDataFlow.cs:286:13:286:36 | SSA def(sink69) | +| LocalDataFlow.cs:290:9:290:37 | SSA def(nonSink0) | LocalDataFlow.cs:291:15:291:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:290:20:290:37 | $"..." | LocalDataFlow.cs:290:9:290:37 | SSA def(nonSink0) | +| LocalDataFlow.cs:291:15:291:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:298:31:298:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:291:15:291:22 | access to local variable nonSink0 | LocalDataFlow.cs:298:31:298:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:294:13:294:34 | SSA def(sink70) | LocalDataFlow.cs:295:15:295:20 | access to local variable sink70 | +| LocalDataFlow.cs:294:22:294:34 | ... = ... | LocalDataFlow.cs:294:13:294:34 | SSA def(sink70) | +| LocalDataFlow.cs:294:22:294:34 | SSA def(sink0) | LocalDataFlow.cs:326:34:326:38 | access to local variable sink0 | +| LocalDataFlow.cs:294:22:294:34 | SSA def(sink0) | LocalDataFlow.cs:327:22:327:26 | access to local variable sink0 | +| LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | LocalDataFlow.cs:294:22:294:34 | ... = ... | +| LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | LocalDataFlow.cs:294:22:294:34 | SSA def(sink0) | +| LocalDataFlow.cs:295:15:295:20 | [post] access to local variable sink70 | LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | +| LocalDataFlow.cs:295:15:295:20 | access to local variable sink70 | LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | +| LocalDataFlow.cs:298:9:298:38 | SSA def(nonSink0) | LocalDataFlow.cs:299:15:299:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:298:20:298:38 | ... = ... | LocalDataFlow.cs:298:9:298:38 | SSA def(nonSink0) | +| LocalDataFlow.cs:298:31:298:38 | access to local variable nonSink0 | LocalDataFlow.cs:298:20:298:38 | ... = ... | +| LocalDataFlow.cs:299:15:299:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | +| LocalDataFlow.cs:299:15:299:22 | access to local variable nonSink0 | LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | +| LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | LocalDataFlow.cs:302:23:302:35 | SSA def(sink71) | +| LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | LocalDataFlow.cs:310:17:310:22 | access to local variable sink70 | +| LocalDataFlow.cs:302:23:302:35 | SSA def(sink71) | LocalDataFlow.cs:303:19:303:24 | access to local variable sink71 | +| LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | LocalDataFlow.cs:306:25:306:40 | SSA def(nonSink16) | +| LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | LocalDataFlow.cs:318:17:318:24 | access to local variable nonSink0 | +| LocalDataFlow.cs:306:25:306:40 | SSA def(nonSink16) | LocalDataFlow.cs:307:19:307:27 | access to local variable nonSink16 | +| LocalDataFlow.cs:310:17:310:22 | access to local variable sink70 | LocalDataFlow.cs:312:18:312:30 | SSA def(sink72) | +| LocalDataFlow.cs:312:18:312:30 | SSA def(sink72) | LocalDataFlow.cs:313:23:313:28 | access to local variable sink72 | +| LocalDataFlow.cs:318:17:318:24 | access to local variable nonSink0 | LocalDataFlow.cs:320:18:320:33 | SSA def(nonSink17) | +| LocalDataFlow.cs:318:17:318:24 | access to local variable nonSink0 | LocalDataFlow.cs:326:22:326:29 | access to local variable nonSink0 | +| LocalDataFlow.cs:320:18:320:33 | SSA def(nonSink17) | LocalDataFlow.cs:321:23:321:31 | access to local variable nonSink17 | +| LocalDataFlow.cs:326:13:326:38 | SSA def(sink73) | LocalDataFlow.cs:328:15:328:20 | access to local variable sink73 | +| LocalDataFlow.cs:326:22:326:29 | access to local variable nonSink0 | LocalDataFlow.cs:326:22:326:38 | ... ?? ... | +| LocalDataFlow.cs:326:22:326:29 | access to local variable nonSink0 | LocalDataFlow.cs:327:31:327:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:326:22:326:38 | ... ?? ... | LocalDataFlow.cs:326:13:326:38 | SSA def(sink73) | +| LocalDataFlow.cs:326:34:326:38 | access to local variable sink0 | LocalDataFlow.cs:326:22:326:38 | ... ?? ... | +| LocalDataFlow.cs:326:34:326:38 | access to local variable sink0 | LocalDataFlow.cs:327:22:327:26 | access to local variable sink0 | +| LocalDataFlow.cs:327:13:327:38 | SSA def(sink74) | LocalDataFlow.cs:329:15:329:20 | access to local variable sink74 | +| LocalDataFlow.cs:327:22:327:26 | access to local variable sink0 | LocalDataFlow.cs:327:22:327:38 | ... ?? ... | +| LocalDataFlow.cs:327:22:327:38 | ... ?? ... | LocalDataFlow.cs:327:13:327:38 | SSA def(sink74) | +| LocalDataFlow.cs:327:31:327:38 | access to local variable nonSink0 | LocalDataFlow.cs:327:22:327:38 | ... ?? ... | +| LocalDataFlow.cs:347:28:347:30 | this | LocalDataFlow.cs:347:41:347:45 | this access | +| LocalDataFlow.cs:347:50:347:52 | this | LocalDataFlow.cs:347:56:347:60 | this access | +| LocalDataFlow.cs:347:50:347:52 | value | LocalDataFlow.cs:347:64:347:68 | access to parameter value | +| LocalDataFlow.cs:353:41:353:47 | tainted | LocalDataFlow.cs:355:15:355:21 | access to parameter tainted | +| LocalDataFlow.cs:358:44:358:53 | nonTainted | LocalDataFlow.cs:360:15:360:24 | access to parameter nonTainted | +| LocalDataFlow.cs:363:44:363:44 | x | LocalDataFlow.cs:366:21:366:21 | access to parameter x | +| LocalDataFlow.cs:363:67:363:68 | os | LocalDataFlow.cs:369:32:369:33 | access to parameter os | +| LocalDataFlow.cs:366:21:366:21 | access to parameter x | LocalDataFlow.cs:366:16:366:21 | ... = ... | +| LocalDataFlow.cs:369:32:369:33 | access to parameter os | LocalDataFlow.cs:369:26:369:33 | ... = ... | +| LocalDataFlow.cs:374:41:374:44 | args | LocalDataFlow.cs:376:29:376:32 | access to parameter args | +| LocalDataFlow.cs:376:29:376:32 | [post] access to parameter args | LocalDataFlow.cs:377:27:377:30 | access to parameter args | +| LocalDataFlow.cs:376:29:376:32 | access to parameter args | LocalDataFlow.cs:377:27:377:30 | access to parameter args | | SSA.cs:5:17:5:17 | SSA entry def(this.S) | SSA.cs:67:9:67:14 | access to field S | | SSA.cs:5:17:5:17 | this | SSA.cs:67:9:67:12 | this access | | SSA.cs:5:26:5:32 | tainted | SSA.cs:8:24:8:30 | access to parameter tainted | diff --git a/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs b/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs index 6603abc50f1..eea36528104 100644 --- a/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs @@ -65,17 +65,6 @@ public class LocalDataFlow nonSink0 += "abc"; Check(nonSink0); - // Assignment (indexer), tainted - var sink2 = new Dictionary(); - sink2[0][1] = sink1; - Check(sink2); - - // Assignment (indexer), not tainted - var nonSink1 = new Dictionary(); - nonSink1[""] = nonSink0; - nonSink1[sink1] = ""; // do not track tainted keys - Check(nonSink1); - // Concatenation, tainted var sink5 = sink1 + "ok"; Check(sink5); @@ -116,30 +105,6 @@ public class LocalDataFlow nonSink3 = nonSink0 as object; Check(nonSink3); - // Array creation (initializer), tainted - var sink10 = new object[] { sink9 }; - Check(sink10); - - // Array creation (initializer), not tainted - var nonSink4 = new object[] { 42 }; - Check(nonSink4); - - // Object creation (collection initializer), tainted - var sink11 = new Dictionary { { "", sink9 } }; - Check(sink11); - - // Object creation (collection initializer), not tainted - nonSink1 = new Dictionary { { sink9, "" } }; - Check(nonSink1); - - // Data-preserving LINQ, tainted - var sink14 = sink11.First(x => x.Value != null); - Check(sink14); - - // Data-preserving LINQ, not tainted - nonSink3 = nonSink1.First(x => x.Value != null); - Check(nonSink1); - // Standard method with a tainted argument, tainted var sink15 = Int32.Parse(sink9); Check(sink15); @@ -206,22 +171,6 @@ public class LocalDataFlow nonSink7 = sink8.Equals(nonSink3); Check(nonSink7); - // Indexer access, tainted - var sink23 = sink11[""]; - Check(sink23); - - // Indexer access, not tainted - nonSink0 = nonSink1[""]; - Check(nonSink0); - - // Array access, tainted - var sink24 = sink10[0]; - Check(sink24); - - // Array access, not tainted - nonSink3 = nonSink4[0]; - Check(nonSink3); - // Logical operation using tainted operand, tainted var sink25 = sink20 || false; Check(sink25); @@ -231,7 +180,7 @@ public class LocalDataFlow Check(nonSink7); // Ad hoc tracking (System.Uri), tainted - var sink26 = new System.Uri(sink23); + var sink26 = new System.Uri(sink9); Check(sink26); var sink27 = sink26.ToString(); Check(sink27); @@ -295,44 +244,6 @@ public class LocalDataFlow nonSink10.AppendLine(nonSink0); Check(nonSink10); - // Ad hoc tracking (System.Lazy), tainted - var sink40 = new Lazy(TaintedMethod); - Check(sink40); - var sink41 = sink40.Value; - Check(sink41); - var sink42 = new Lazy(() => "taint source"); - Check(sink42); - var sink43 = sink42.Value; - Check(sink43); - - // Ad hoc tracking (System.Lazy), not tainted - var nonSink12 = new Lazy(NonTaintedMethod); - Check(nonSink12); - nonSink0 = nonSink12.Value; - Check(nonSink0); - nonSink12 = new Lazy(() => ""); - Check(nonSink12); - nonSink0 = nonSink12.Value; - Check(nonSink0); - - // Ad hoc tracking (collections), tainted - var sink3 = new Dictionary(); - sink3.Add(0, sink1); - Check(sink3); - var sink12 = sink3.Values; - Check(sink12); - var sink13 = sink12.Reverse(); - Check(sink13); - - // Ad hoc tracking (collections), not tainted - nonSink1.Add("", nonSink0); - nonSink1.Add(sink1, ""); // do not track tainted keys - Check(nonSink1); - var nonSink5 = nonSink1.Values; - Check(nonSink5); - var nonSink6 = nonSink5.Reverse(); - Check(nonSink6); - // Ad hoc tracking (data contracts), tainted var taintedDataContract = new DataContract(); var sink53 = taintedDataContract.AString; @@ -359,34 +270,6 @@ public class LocalDataFlow nonSink0 = nonTaintedTextBox.Text; Check(nonSink0); - // Iteration over a tracked expression, tainted - foreach (var sink61 in sink10) - Check(sink61); - IEnumerator sink62 = sink10.GetEnumerator(); - Check(sink62); - var sink63 = sink62.Current; - Check(sink63); - IEnumerator> sink64 = sink3.GetEnumerator(); - Check(sink64); - var sink65 = sink64.Current; - Check(sink65); - var sink66 = sink65.Value; - Check(sink66); - - // Iteration over a tracked expression, not tainted - foreach (var nonSink17 in nonSink4) - Check(nonSink17); - IEnumerator nonSink18 = nonSink4.GetEnumerator(); - Check(nonSink18); - nonSink3 = nonSink18.Current; - Check(nonSink3); - IEnumerator> nonSink19 = nonSink1.GetEnumerator(); - Check(nonSink19); - var nonSink20 = nonSink19.Current; - Check(nonSink20); - nonSink0 = nonSink20.Value; - Check(nonSink0); - // async await, tainted var sink67 = Task.Run(() => "taint source"); Check(sink67); diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected b/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected index 756d79333c1..e8a0153dc92 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected @@ -1,70 +1,51 @@ | LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | | LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | -| LocalDataFlow.cs:71:15:71:19 | access to local variable sink2 | -| LocalDataFlow.cs:81:15:81:19 | access to local variable sink5 | -| LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | -| LocalDataFlow.cs:97:15:97:19 | [b (line 49): false] access to local variable sink7 | -| LocalDataFlow.cs:97:15:97:19 | [b (line 49): true] access to local variable sink7 | -| LocalDataFlow.cs:105:15:105:19 | access to local variable sink8 | -| LocalDataFlow.cs:113:15:113:19 | access to local variable sink9 | -| LocalDataFlow.cs:121:15:121:20 | access to local variable sink10 | -| LocalDataFlow.cs:129:15:129:20 | access to local variable sink11 | -| LocalDataFlow.cs:137:15:137:20 | access to local variable sink14 | -| LocalDataFlow.cs:145:15:145:20 | access to local variable sink15 | -| LocalDataFlow.cs:148:15:148:20 | access to local variable sink16 | -| LocalDataFlow.cs:150:15:150:20 | access to local variable sink17 | -| LocalDataFlow.cs:152:15:152:20 | access to local variable sink18 | -| LocalDataFlow.cs:154:15:154:20 | access to local variable sink19 | -| LocalDataFlow.cs:156:15:156:20 | access to local variable sink45 | -| LocalDataFlow.cs:159:15:159:20 | access to local variable sink46 | -| LocalDataFlow.cs:161:15:161:20 | access to local variable sink47 | -| LocalDataFlow.cs:163:15:163:20 | access to local variable sink49 | -| LocalDataFlow.cs:165:15:165:20 | access to local variable sink50 | -| LocalDataFlow.cs:167:15:167:20 | access to local variable sink51 | -| LocalDataFlow.cs:169:15:169:20 | access to local variable sink52 | -| LocalDataFlow.cs:197:15:197:20 | access to local variable sink20 | -| LocalDataFlow.cs:199:15:199:20 | access to local variable sink21 | -| LocalDataFlow.cs:201:15:201:20 | access to local variable sink22 | -| LocalDataFlow.cs:211:15:211:20 | access to local variable sink23 | -| LocalDataFlow.cs:219:15:219:20 | access to local variable sink24 | -| LocalDataFlow.cs:227:15:227:20 | access to local variable sink25 | -| LocalDataFlow.cs:235:15:235:20 | access to local variable sink26 | -| LocalDataFlow.cs:237:15:237:20 | access to local variable sink27 | -| LocalDataFlow.cs:239:15:239:20 | access to local variable sink28 | -| LocalDataFlow.cs:241:15:241:20 | access to local variable sink29 | -| LocalDataFlow.cs:243:15:243:20 | access to local variable sink30 | -| LocalDataFlow.cs:259:15:259:20 | access to local variable sink31 | -| LocalDataFlow.cs:261:15:261:20 | access to local variable sink32 | -| LocalDataFlow.cs:271:15:271:20 | access to local variable sink33 | -| LocalDataFlow.cs:273:15:273:20 | access to local variable sink48 | -| LocalDataFlow.cs:283:15:283:20 | access to local variable sink34 | -| LocalDataFlow.cs:285:15:285:20 | access to local variable sink35 | -| LocalDataFlow.cs:288:15:288:20 | access to local variable sink36 | -| LocalDataFlow.cs:300:15:300:20 | access to local variable sink40 | -| LocalDataFlow.cs:302:15:302:20 | access to local variable sink41 | -| LocalDataFlow.cs:304:15:304:20 | access to local variable sink42 | -| LocalDataFlow.cs:306:15:306:20 | access to local variable sink43 | -| LocalDataFlow.cs:321:15:321:19 | access to local variable sink3 | -| LocalDataFlow.cs:323:15:323:20 | access to local variable sink12 | -| LocalDataFlow.cs:325:15:325:20 | access to local variable sink13 | -| LocalDataFlow.cs:339:15:339:20 | access to local variable sink53 | -| LocalDataFlow.cs:341:15:341:20 | access to local variable sink54 | -| LocalDataFlow.cs:355:15:355:20 | access to local variable sink60 | -| LocalDataFlow.cs:364:19:364:24 | access to local variable sink61 | -| LocalDataFlow.cs:366:15:366:20 | access to local variable sink62 | -| LocalDataFlow.cs:368:15:368:20 | access to local variable sink63 | -| LocalDataFlow.cs:370:15:370:20 | access to local variable sink64 | -| LocalDataFlow.cs:372:15:372:20 | access to local variable sink65 | -| LocalDataFlow.cs:374:15:374:20 | access to local variable sink66 | -| LocalDataFlow.cs:392:15:392:20 | access to local variable sink67 | -| LocalDataFlow.cs:394:15:394:20 | access to local variable sink68 | -| LocalDataFlow.cs:404:15:404:20 | access to local variable sink69 | -| LocalDataFlow.cs:412:15:412:20 | access to local variable sink70 | -| LocalDataFlow.cs:420:19:420:24 | access to local variable sink71 | -| LocalDataFlow.cs:430:23:430:28 | access to local variable sink72 | -| LocalDataFlow.cs:445:15:445:20 | access to local variable sink73 | -| LocalDataFlow.cs:446:15:446:20 | access to local variable sink74 | -| LocalDataFlow.cs:472:15:472:21 | access to parameter tainted | +| LocalDataFlow.cs:70:15:70:19 | access to local variable sink5 | +| LocalDataFlow.cs:78:15:78:19 | access to local variable sink6 | +| LocalDataFlow.cs:86:15:86:19 | [b (line 49): false] access to local variable sink7 | +| LocalDataFlow.cs:86:15:86:19 | [b (line 49): true] access to local variable sink7 | +| LocalDataFlow.cs:94:15:94:19 | access to local variable sink8 | +| LocalDataFlow.cs:102:15:102:19 | access to local variable sink9 | +| LocalDataFlow.cs:110:15:110:20 | access to local variable sink15 | +| LocalDataFlow.cs:113:15:113:20 | access to local variable sink16 | +| LocalDataFlow.cs:115:15:115:20 | access to local variable sink17 | +| LocalDataFlow.cs:117:15:117:20 | access to local variable sink18 | +| LocalDataFlow.cs:119:15:119:20 | access to local variable sink19 | +| LocalDataFlow.cs:121:15:121:20 | access to local variable sink45 | +| LocalDataFlow.cs:124:15:124:20 | access to local variable sink46 | +| LocalDataFlow.cs:126:15:126:20 | access to local variable sink47 | +| LocalDataFlow.cs:128:15:128:20 | access to local variable sink49 | +| LocalDataFlow.cs:130:15:130:20 | access to local variable sink50 | +| LocalDataFlow.cs:132:15:132:20 | access to local variable sink51 | +| LocalDataFlow.cs:134:15:134:20 | access to local variable sink52 | +| LocalDataFlow.cs:162:15:162:20 | access to local variable sink20 | +| LocalDataFlow.cs:164:15:164:20 | access to local variable sink21 | +| LocalDataFlow.cs:166:15:166:20 | access to local variable sink22 | +| LocalDataFlow.cs:176:15:176:20 | access to local variable sink25 | +| LocalDataFlow.cs:184:15:184:20 | access to local variable sink26 | +| LocalDataFlow.cs:186:15:186:20 | access to local variable sink27 | +| LocalDataFlow.cs:188:15:188:20 | access to local variable sink28 | +| LocalDataFlow.cs:190:15:190:20 | access to local variable sink29 | +| LocalDataFlow.cs:192:15:192:20 | access to local variable sink30 | +| LocalDataFlow.cs:208:15:208:20 | access to local variable sink31 | +| LocalDataFlow.cs:210:15:210:20 | access to local variable sink32 | +| LocalDataFlow.cs:220:15:220:20 | access to local variable sink33 | +| LocalDataFlow.cs:222:15:222:20 | access to local variable sink48 | +| LocalDataFlow.cs:232:15:232:20 | access to local variable sink34 | +| LocalDataFlow.cs:234:15:234:20 | access to local variable sink35 | +| LocalDataFlow.cs:237:15:237:20 | access to local variable sink36 | +| LocalDataFlow.cs:250:15:250:20 | access to local variable sink53 | +| LocalDataFlow.cs:252:15:252:20 | access to local variable sink54 | +| LocalDataFlow.cs:266:15:266:20 | access to local variable sink60 | +| LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | +| LocalDataFlow.cs:277:15:277:20 | access to local variable sink68 | +| LocalDataFlow.cs:287:15:287:20 | access to local variable sink69 | +| LocalDataFlow.cs:295:15:295:20 | access to local variable sink70 | +| LocalDataFlow.cs:303:19:303:24 | access to local variable sink71 | +| LocalDataFlow.cs:313:23:313:28 | access to local variable sink72 | +| LocalDataFlow.cs:328:15:328:20 | access to local variable sink73 | +| LocalDataFlow.cs:329:15:329:20 | access to local variable sink74 | +| LocalDataFlow.cs:355:15:355:21 | access to parameter tainted | | SSA.cs:9:15:9:22 | access to local variable ssaSink0 | | SSA.cs:25:15:25:22 | access to local variable ssaSink1 | | SSA.cs:43:15:43:22 | access to local variable ssaSink2 | diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected index 8dd765a23cd..4cb33d841cb 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected @@ -24,9 +24,8 @@ | Capture.cs:58:21:58:21 | 1 | Capture.cs:58:17:58:21 | SSA def(i) | | Capture.cs:61:17:61:17 | 1 | Capture.cs:61:13:61:17 | SSA def(i) | | Capture.cs:63:9:63:17 | SSA call def(i) | Capture.cs:64:13:64:13 | access to local variable i | -| LocalDataFlow.cs:49:23:49:23 | this | LocalDataFlow.cs:299:39:299:51 | this access | | LocalDataFlow.cs:49:30:49:30 | b | LocalDataFlow.cs:49:30:49:30 | b | -| LocalDataFlow.cs:49:30:49:30 | b | LocalDataFlow.cs:96:21:96:21 | access to parameter b | +| LocalDataFlow.cs:49:30:49:30 | b | LocalDataFlow.cs:85:21:85:21 | access to parameter b | | LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | | LocalDataFlow.cs:52:21:52:34 | "taint source" | LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | | LocalDataFlow.cs:53:15:53:19 | [post] access to local variable sink0 | LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | @@ -41,713 +40,508 @@ | LocalDataFlow.cs:61:9:61:22 | ... + ... | LocalDataFlow.cs:61:9:61:22 | SSA def(sink1) | | LocalDataFlow.cs:61:9:61:22 | SSA def(sink1) | LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | | LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | LocalDataFlow.cs:61:9:61:22 | ... + ... | -| LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | LocalDataFlow.cs:204:20:204:24 | access to local variable sink0 | -| LocalDataFlow.cs:62:15:62:19 | [post] access to local variable sink1 | LocalDataFlow.cs:70:23:70:27 | access to local variable sink1 | -| LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | LocalDataFlow.cs:70:23:70:27 | access to local variable sink1 | +| LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | LocalDataFlow.cs:169:20:169:24 | access to local variable sink0 | +| LocalDataFlow.cs:62:15:62:19 | [post] access to local variable sink1 | LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | +| LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | | LocalDataFlow.cs:65:9:65:16 | access to local variable nonSink0 | LocalDataFlow.cs:65:9:65:25 | ... + ... | | LocalDataFlow.cs:65:9:65:25 | ... + ... | LocalDataFlow.cs:65:9:65:25 | SSA def(nonSink0) | | LocalDataFlow.cs:65:9:65:25 | SSA def(nonSink0) | LocalDataFlow.cs:66:15:66:22 | access to local variable nonSink0 | | LocalDataFlow.cs:65:21:65:25 | "abc" | LocalDataFlow.cs:65:9:65:25 | ... + ... | -| LocalDataFlow.cs:66:15:66:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:75:24:75:31 | access to local variable nonSink0 | -| LocalDataFlow.cs:66:15:66:22 | access to local variable nonSink0 | LocalDataFlow.cs:75:24:75:31 | access to local variable nonSink0 | -| LocalDataFlow.cs:69:13:69:51 | SSA def(sink2) | LocalDataFlow.cs:70:9:70:13 | access to local variable sink2 | -| LocalDataFlow.cs:69:21:69:51 | object creation of type Dictionary | LocalDataFlow.cs:69:13:69:51 | SSA def(sink2) | -| LocalDataFlow.cs:70:9:70:13 | [post] access to local variable sink2 | LocalDataFlow.cs:71:15:71:19 | access to local variable sink2 | -| LocalDataFlow.cs:70:9:70:13 | access to local variable sink2 | LocalDataFlow.cs:70:9:70:16 | access to indexer | -| LocalDataFlow.cs:70:9:70:13 | access to local variable sink2 | LocalDataFlow.cs:71:15:71:19 | access to local variable sink2 | -| LocalDataFlow.cs:70:23:70:27 | access to local variable sink1 | LocalDataFlow.cs:70:9:70:13 | access to local variable sink2 | -| LocalDataFlow.cs:70:23:70:27 | access to local variable sink1 | LocalDataFlow.cs:70:9:70:16 | access to indexer | -| LocalDataFlow.cs:70:23:70:27 | access to local variable sink1 | LocalDataFlow.cs:76:18:76:22 | access to local variable sink1 | -| LocalDataFlow.cs:74:13:74:55 | SSA def(nonSink1) | LocalDataFlow.cs:75:9:75:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:74:24:74:55 | object creation of type Dictionary | LocalDataFlow.cs:74:13:74:55 | SSA def(nonSink1) | -| LocalDataFlow.cs:75:9:75:16 | [post] access to local variable nonSink1 | LocalDataFlow.cs:76:9:76:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:75:9:75:16 | access to local variable nonSink1 | LocalDataFlow.cs:75:9:75:20 | access to indexer | -| LocalDataFlow.cs:75:9:75:16 | access to local variable nonSink1 | LocalDataFlow.cs:76:9:76:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:75:24:75:31 | [post] access to local variable nonSink0 | LocalDataFlow.cs:84:20:84:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:75:24:75:31 | access to local variable nonSink0 | LocalDataFlow.cs:75:9:75:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:75:24:75:31 | access to local variable nonSink0 | LocalDataFlow.cs:84:20:84:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:76:9:76:16 | [post] access to local variable nonSink1 | LocalDataFlow.cs:77:15:77:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:76:9:76:16 | access to local variable nonSink1 | LocalDataFlow.cs:76:9:76:23 | access to indexer | -| LocalDataFlow.cs:76:9:76:16 | access to local variable nonSink1 | LocalDataFlow.cs:77:15:77:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:76:18:76:22 | [post] access to local variable sink1 | LocalDataFlow.cs:80:21:80:25 | access to local variable sink1 | -| LocalDataFlow.cs:76:18:76:22 | access to local variable sink1 | LocalDataFlow.cs:80:21:80:25 | access to local variable sink1 | -| LocalDataFlow.cs:76:27:76:28 | "" | LocalDataFlow.cs:76:9:76:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:80:13:80:32 | SSA def(sink5) | LocalDataFlow.cs:81:15:81:19 | access to local variable sink5 | -| LocalDataFlow.cs:80:21:80:25 | access to local variable sink1 | LocalDataFlow.cs:80:21:80:32 | ... + ... | -| LocalDataFlow.cs:80:21:80:25 | access to local variable sink1 | LocalDataFlow.cs:204:33:204:37 | access to local variable sink1 | -| LocalDataFlow.cs:80:21:80:32 | ... + ... | LocalDataFlow.cs:80:13:80:32 | SSA def(sink5) | -| LocalDataFlow.cs:80:29:80:32 | "ok" | LocalDataFlow.cs:80:21:80:32 | ... + ... | -| LocalDataFlow.cs:81:15:81:19 | [post] access to local variable sink5 | LocalDataFlow.cs:88:22:88:26 | access to local variable sink5 | -| LocalDataFlow.cs:81:15:81:19 | access to local variable sink5 | LocalDataFlow.cs:88:22:88:26 | access to local variable sink5 | -| LocalDataFlow.cs:84:9:84:36 | SSA def(nonSink0) | LocalDataFlow.cs:85:15:85:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:84:20:84:27 | access to local variable nonSink0 | LocalDataFlow.cs:84:20:84:36 | ... + ... | -| LocalDataFlow.cs:84:20:84:36 | ... + ... | LocalDataFlow.cs:84:9:84:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:84:31:84:36 | "test" | LocalDataFlow.cs:84:20:84:36 | ... + ... | -| LocalDataFlow.cs:85:15:85:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:92:21:92:28 | access to local variable nonSink0 | -| LocalDataFlow.cs:85:15:85:22 | access to local variable nonSink0 | LocalDataFlow.cs:92:21:92:28 | access to local variable nonSink0 | -| LocalDataFlow.cs:88:13:88:27 | SSA def(sink6) | LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | -| LocalDataFlow.cs:88:22:88:26 | access to local variable sink5 | LocalDataFlow.cs:88:13:88:27 | SSA def(sink6) | -| LocalDataFlow.cs:89:15:89:19 | [post] access to local variable sink6 | LocalDataFlow.cs:96:31:96:35 | [b (line 49): false] access to local variable sink6 | -| LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | LocalDataFlow.cs:96:31:96:35 | [b (line 49): false] access to local variable sink6 | -| LocalDataFlow.cs:92:9:92:29 | SSA def(nonSink0) | LocalDataFlow.cs:93:15:93:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:92:21:92:28 | access to local variable nonSink0 | LocalDataFlow.cs:92:9:92:29 | SSA def(nonSink0) | -| LocalDataFlow.cs:96:13:96:35 | [b (line 49): false] SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | [b (line 49): false] access to local variable sink7 | -| LocalDataFlow.cs:96:13:96:35 | [b (line 49): true] SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | [b (line 49): true] access to local variable sink7 | -| LocalDataFlow.cs:96:21:96:21 | access to parameter b | LocalDataFlow.cs:100:20:100:20 | [b (line 49): false] access to parameter b | -| LocalDataFlow.cs:96:21:96:21 | access to parameter b | LocalDataFlow.cs:100:20:100:20 | [b (line 49): true] access to parameter b | -| LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | LocalDataFlow.cs:96:13:96:35 | [b (line 49): false] SSA def(sink7) | -| LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | LocalDataFlow.cs:96:13:96:35 | [b (line 49): true] SSA def(sink7) | -| LocalDataFlow.cs:96:25:96:27 | [b (line 49): true] "a" | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | -| LocalDataFlow.cs:96:31:96:35 | [b (line 49): false] access to local variable sink6 | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | -| LocalDataFlow.cs:97:15:97:19 | [b (line 49): false] access to local variable sink7 | LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | -| LocalDataFlow.cs:97:15:97:19 | [b (line 49): true] access to local variable sink7 | LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | -| LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | LocalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | LocalDataFlow.cs:104:29:104:33 | access to local variable sink7 | -| LocalDataFlow.cs:100:20:100:36 | [b (line 49): false] ... ? ... : ... | LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:100:20:100:36 | [b (line 49): true] ... ? ... : ... | LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:100:24:100:28 | "abc" | LocalDataFlow.cs:100:20:100:36 | [b (line 49): true] ... ? ... : ... | -| LocalDataFlow.cs:100:32:100:36 | "def" | LocalDataFlow.cs:100:20:100:36 | [b (line 49): false] ... ? ... : ... | -| LocalDataFlow.cs:101:15:101:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:108:32:108:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | LocalDataFlow.cs:108:32:108:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:104:13:104:33 | SSA def(sink8) | LocalDataFlow.cs:105:15:105:19 | access to local variable sink8 | -| LocalDataFlow.cs:104:21:104:33 | (...) ... | LocalDataFlow.cs:104:13:104:33 | SSA def(sink8) | -| LocalDataFlow.cs:104:29:104:33 | access to local variable sink7 | LocalDataFlow.cs:104:21:104:33 | (...) ... | -| LocalDataFlow.cs:105:15:105:19 | [post] access to local variable sink8 | LocalDataFlow.cs:112:21:112:25 | access to local variable sink8 | -| LocalDataFlow.cs:105:15:105:19 | access to local variable sink8 | LocalDataFlow.cs:112:21:112:25 | access to local variable sink8 | -| LocalDataFlow.cs:108:13:108:39 | SSA def(nonSink3) | LocalDataFlow.cs:109:15:109:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:108:24:108:39 | (...) ... | LocalDataFlow.cs:108:13:108:39 | SSA def(nonSink3) | -| LocalDataFlow.cs:108:32:108:39 | access to local variable nonSink0 | LocalDataFlow.cs:108:24:108:39 | (...) ... | -| LocalDataFlow.cs:108:32:108:39 | access to local variable nonSink0 | LocalDataFlow.cs:116:20:116:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:112:13:112:35 | SSA def(sink9) | LocalDataFlow.cs:113:15:113:19 | access to local variable sink9 | -| LocalDataFlow.cs:112:21:112:25 | access to local variable sink8 | LocalDataFlow.cs:112:21:112:35 | ... as ... | -| LocalDataFlow.cs:112:21:112:25 | access to local variable sink8 | LocalDataFlow.cs:200:22:200:26 | access to local variable sink8 | -| LocalDataFlow.cs:112:21:112:35 | ... as ... | LocalDataFlow.cs:112:13:112:35 | SSA def(sink9) | -| LocalDataFlow.cs:113:15:113:19 | [post] access to local variable sink9 | LocalDataFlow.cs:120:37:120:41 | access to local variable sink9 | -| LocalDataFlow.cs:113:15:113:19 | access to local variable sink9 | LocalDataFlow.cs:120:37:120:41 | access to local variable sink9 | -| LocalDataFlow.cs:116:9:116:37 | SSA def(nonSink3) | LocalDataFlow.cs:117:15:117:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:116:20:116:27 | access to local variable nonSink0 | LocalDataFlow.cs:116:20:116:37 | ... as ... | -| LocalDataFlow.cs:116:20:116:27 | access to local variable nonSink0 | LocalDataFlow.cs:149:22:149:29 | access to local variable nonSink0 | -| LocalDataFlow.cs:116:20:116:37 | ... as ... | LocalDataFlow.cs:116:9:116:37 | SSA def(nonSink3) | -| LocalDataFlow.cs:120:13:120:43 | SSA def(sink10) | LocalDataFlow.cs:121:15:121:20 | access to local variable sink10 | -| LocalDataFlow.cs:120:22:120:43 | array creation of type Object[] | LocalDataFlow.cs:120:13:120:43 | SSA def(sink10) | -| LocalDataFlow.cs:120:37:120:41 | access to local variable sink9 | LocalDataFlow.cs:120:22:120:43 | array creation of type Object[] | -| LocalDataFlow.cs:120:37:120:41 | access to local variable sink9 | LocalDataFlow.cs:128:61:128:65 | access to local variable sink9 | -| LocalDataFlow.cs:121:15:121:20 | [post] access to local variable sink10 | LocalDataFlow.cs:218:22:218:27 | access to local variable sink10 | -| LocalDataFlow.cs:121:15:121:20 | access to local variable sink10 | LocalDataFlow.cs:218:22:218:27 | access to local variable sink10 | -| LocalDataFlow.cs:124:13:124:42 | SSA def(nonSink4) | LocalDataFlow.cs:125:15:125:22 | access to local variable nonSink4 | -| LocalDataFlow.cs:124:24:124:42 | array creation of type Object[] | LocalDataFlow.cs:124:13:124:42 | SSA def(nonSink4) | -| LocalDataFlow.cs:124:39:124:40 | 42 | LocalDataFlow.cs:124:39:124:40 | (...) ... | -| LocalDataFlow.cs:124:39:124:40 | (...) ... | LocalDataFlow.cs:124:24:124:42 | array creation of type Object[] | -| LocalDataFlow.cs:125:15:125:22 | [post] access to local variable nonSink4 | LocalDataFlow.cs:222:20:222:27 | access to local variable nonSink4 | -| LocalDataFlow.cs:125:15:125:22 | access to local variable nonSink4 | LocalDataFlow.cs:222:20:222:27 | access to local variable nonSink4 | -| LocalDataFlow.cs:128:13:128:69 | SSA def(sink11) | LocalDataFlow.cs:129:15:129:20 | access to local variable sink11 | -| LocalDataFlow.cs:128:22:128:69 | object creation of type Dictionary | LocalDataFlow.cs:128:13:128:69 | SSA def(sink11) | -| LocalDataFlow.cs:128:61:128:65 | [post] access to local variable sink9 | LocalDataFlow.cs:132:55:132:59 | access to local variable sink9 | -| LocalDataFlow.cs:128:61:128:65 | access to local variable sink9 | LocalDataFlow.cs:128:22:128:69 | object creation of type Dictionary | -| LocalDataFlow.cs:128:61:128:65 | access to local variable sink9 | LocalDataFlow.cs:132:55:132:59 | access to local variable sink9 | -| LocalDataFlow.cs:129:15:129:20 | [post] access to local variable sink11 | LocalDataFlow.cs:136:22:136:27 | access to local variable sink11 | -| LocalDataFlow.cs:129:15:129:20 | access to local variable sink11 | LocalDataFlow.cs:136:22:136:27 | access to local variable sink11 | -| LocalDataFlow.cs:132:9:132:67 | SSA def(nonSink1) | LocalDataFlow.cs:133:15:133:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:132:20:132:67 | object creation of type Dictionary | LocalDataFlow.cs:132:9:132:67 | SSA def(nonSink1) | -| LocalDataFlow.cs:132:55:132:59 | [post] access to local variable sink9 | LocalDataFlow.cs:144:34:144:38 | access to local variable sink9 | -| LocalDataFlow.cs:132:55:132:59 | access to local variable sink9 | LocalDataFlow.cs:144:34:144:38 | access to local variable sink9 | -| LocalDataFlow.cs:132:62:132:63 | "" | LocalDataFlow.cs:132:20:132:67 | object creation of type Dictionary | -| LocalDataFlow.cs:133:15:133:22 | [post] access to local variable nonSink1 | LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink1 | -| LocalDataFlow.cs:133:15:133:22 | access to local variable nonSink1 | LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink1 | -| LocalDataFlow.cs:136:13:136:55 | SSA def(sink14) | LocalDataFlow.cs:137:15:137:20 | access to local variable sink14 | -| LocalDataFlow.cs:136:22:136:27 | [post] access to local variable sink11 | LocalDataFlow.cs:210:22:210:27 | access to local variable sink11 | -| LocalDataFlow.cs:136:22:136:27 | access to local variable sink11 | LocalDataFlow.cs:136:22:136:55 | call to method First | -| LocalDataFlow.cs:136:22:136:27 | access to local variable sink11 | LocalDataFlow.cs:210:22:210:27 | access to local variable sink11 | -| LocalDataFlow.cs:136:22:136:55 | call to method First | LocalDataFlow.cs:136:13:136:55 | SSA def(sink14) | -| LocalDataFlow.cs:136:35:136:35 | x | LocalDataFlow.cs:136:35:136:35 | x | -| LocalDataFlow.cs:136:35:136:35 | x | LocalDataFlow.cs:136:40:136:40 | access to parameter x | -| LocalDataFlow.cs:136:40:136:40 | access to parameter x | LocalDataFlow.cs:136:40:136:46 | access to property Value | -| LocalDataFlow.cs:136:40:136:46 | access to property Value | LocalDataFlow.cs:136:40:136:54 | ... != ... | -| LocalDataFlow.cs:140:9:140:55 | SSA def(nonSink3) | LocalDataFlow.cs:206:33:206:40 | access to local variable nonSink3 | -| LocalDataFlow.cs:140:20:140:27 | [post] access to local variable nonSink1 | LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink1 | LocalDataFlow.cs:140:20:140:55 | call to method First | -| LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink1 | LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:140:20:140:55 | (...) ... | LocalDataFlow.cs:140:9:140:55 | SSA def(nonSink3) | -| LocalDataFlow.cs:140:20:140:55 | call to method First | LocalDataFlow.cs:140:20:140:55 | (...) ... | -| LocalDataFlow.cs:140:35:140:35 | x | LocalDataFlow.cs:140:35:140:35 | x | -| LocalDataFlow.cs:140:35:140:35 | x | LocalDataFlow.cs:140:40:140:40 | access to parameter x | -| LocalDataFlow.cs:140:40:140:40 | access to parameter x | LocalDataFlow.cs:140:40:140:46 | access to property Value | -| LocalDataFlow.cs:140:40:140:46 | access to property Value | LocalDataFlow.cs:140:40:140:54 | ... != ... | -| LocalDataFlow.cs:141:15:141:22 | [post] access to local variable nonSink1 | LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink1 | -| LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink1 | LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink1 | -| LocalDataFlow.cs:144:13:144:39 | SSA def(sink15) | LocalDataFlow.cs:145:15:145:20 | access to local variable sink15 | -| LocalDataFlow.cs:144:22:144:39 | call to method Parse | LocalDataFlow.cs:144:13:144:39 | SSA def(sink15) | -| LocalDataFlow.cs:144:34:144:38 | [post] access to local variable sink9 | LocalDataFlow.cs:147:37:147:41 | access to local variable sink9 | -| LocalDataFlow.cs:144:34:144:38 | access to local variable sink9 | LocalDataFlow.cs:144:22:144:39 | call to method Parse | -| LocalDataFlow.cs:144:34:144:38 | access to local variable sink9 | LocalDataFlow.cs:147:37:147:41 | access to local variable sink9 | -| LocalDataFlow.cs:145:15:145:20 | access to local variable sink15 | LocalDataFlow.cs:196:22:196:27 | access to local variable sink15 | -| LocalDataFlow.cs:147:13:147:56 | SSA def(sink16) | LocalDataFlow.cs:148:15:148:20 | access to local variable sink16 | -| LocalDataFlow.cs:147:22:147:56 | call to method TryParse | LocalDataFlow.cs:147:13:147:56 | SSA def(sink16) | -| LocalDataFlow.cs:147:37:147:41 | [post] access to local variable sink9 | LocalDataFlow.cs:149:44:149:48 | access to local variable sink9 | -| LocalDataFlow.cs:147:37:147:41 | access to local variable sink9 | LocalDataFlow.cs:147:22:147:56 | call to method TryParse | -| LocalDataFlow.cs:147:37:147:41 | access to local variable sink9 | LocalDataFlow.cs:149:44:149:48 | access to local variable sink9 | -| LocalDataFlow.cs:149:13:149:49 | SSA def(sink17) | LocalDataFlow.cs:150:15:150:20 | access to local variable sink17 | -| LocalDataFlow.cs:149:22:149:29 | [post] access to local variable nonSink0 | LocalDataFlow.cs:151:36:151:43 | access to local variable nonSink0 | -| LocalDataFlow.cs:149:22:149:29 | access to local variable nonSink0 | LocalDataFlow.cs:149:22:149:49 | call to method Replace | -| LocalDataFlow.cs:149:22:149:29 | access to local variable nonSink0 | LocalDataFlow.cs:151:36:151:43 | access to local variable nonSink0 | -| LocalDataFlow.cs:149:22:149:49 | call to method Replace | LocalDataFlow.cs:149:13:149:49 | SSA def(sink17) | -| LocalDataFlow.cs:149:44:149:48 | [post] access to local variable sink9 | LocalDataFlow.cs:151:46:151:50 | access to local variable sink9 | -| LocalDataFlow.cs:149:44:149:48 | access to local variable sink9 | LocalDataFlow.cs:149:22:149:49 | call to method Replace | -| LocalDataFlow.cs:149:44:149:48 | access to local variable sink9 | LocalDataFlow.cs:151:46:151:50 | access to local variable sink9 | -| LocalDataFlow.cs:151:13:151:51 | SSA def(sink18) | LocalDataFlow.cs:152:15:152:20 | access to local variable sink18 | -| LocalDataFlow.cs:151:22:151:51 | call to method Format | LocalDataFlow.cs:151:13:151:51 | SSA def(sink18) | -| LocalDataFlow.cs:151:36:151:43 | [post] access to local variable nonSink0 | LocalDataFlow.cs:153:44:153:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:151:36:151:43 | access to local variable nonSink0 | LocalDataFlow.cs:151:22:151:51 | call to method Format | -| LocalDataFlow.cs:151:36:151:43 | access to local variable nonSink0 | LocalDataFlow.cs:153:44:153:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:151:46:151:50 | [post] access to local variable sink9 | LocalDataFlow.cs:155:33:155:37 | access to local variable sink9 | -| LocalDataFlow.cs:151:46:151:50 | access to local variable sink9 | LocalDataFlow.cs:151:22:151:51 | call to method Format | -| LocalDataFlow.cs:151:46:151:50 | access to local variable sink9 | LocalDataFlow.cs:155:33:155:37 | access to local variable sink9 | -| LocalDataFlow.cs:152:15:152:20 | [post] access to local variable sink18 | LocalDataFlow.cs:153:36:153:41 | access to local variable sink18 | -| LocalDataFlow.cs:152:15:152:20 | access to local variable sink18 | LocalDataFlow.cs:153:36:153:41 | access to local variable sink18 | -| LocalDataFlow.cs:153:13:153:52 | SSA def(sink19) | LocalDataFlow.cs:154:15:154:20 | access to local variable sink19 | -| LocalDataFlow.cs:153:22:153:52 | call to method Format | LocalDataFlow.cs:153:13:153:52 | SSA def(sink19) | -| LocalDataFlow.cs:153:36:153:41 | access to local variable sink18 | LocalDataFlow.cs:153:22:153:52 | call to method Format | -| LocalDataFlow.cs:153:44:153:51 | [post] access to local variable nonSink0 | LocalDataFlow.cs:172:32:172:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:153:44:153:51 | access to local variable nonSink0 | LocalDataFlow.cs:153:22:153:52 | call to method Format | -| LocalDataFlow.cs:153:44:153:51 | access to local variable nonSink0 | LocalDataFlow.cs:172:32:172:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:155:13:155:38 | SSA def(sink45) | LocalDataFlow.cs:156:15:156:20 | access to local variable sink45 | -| LocalDataFlow.cs:155:22:155:38 | call to method Parse | LocalDataFlow.cs:155:13:155:38 | SSA def(sink45) | -| LocalDataFlow.cs:155:33:155:37 | [post] access to local variable sink9 | LocalDataFlow.cs:158:36:158:40 | access to local variable sink9 | -| LocalDataFlow.cs:155:33:155:37 | access to local variable sink9 | LocalDataFlow.cs:155:22:155:38 | call to method Parse | -| LocalDataFlow.cs:155:33:155:37 | access to local variable sink9 | LocalDataFlow.cs:158:36:158:40 | access to local variable sink9 | -| LocalDataFlow.cs:158:13:158:56 | SSA def(sink46) | LocalDataFlow.cs:159:15:159:20 | access to local variable sink46 | -| LocalDataFlow.cs:158:22:158:56 | call to method TryParse | LocalDataFlow.cs:158:13:158:56 | SSA def(sink46) | -| LocalDataFlow.cs:158:36:158:40 | [post] access to local variable sink9 | LocalDataFlow.cs:198:22:198:26 | access to local variable sink9 | -| LocalDataFlow.cs:158:36:158:40 | access to local variable sink9 | LocalDataFlow.cs:158:22:158:56 | call to method TryParse | -| LocalDataFlow.cs:158:36:158:40 | access to local variable sink9 | LocalDataFlow.cs:198:22:198:26 | access to local variable sink9 | -| LocalDataFlow.cs:159:15:159:20 | access to local variable sink46 | LocalDataFlow.cs:160:37:160:42 | access to local variable sink46 | -| LocalDataFlow.cs:160:13:160:43 | SSA def(sink47) | LocalDataFlow.cs:161:15:161:20 | access to local variable sink47 | -| LocalDataFlow.cs:160:22:160:43 | call to method ToByte | LocalDataFlow.cs:160:13:160:43 | SSA def(sink47) | -| LocalDataFlow.cs:160:37:160:42 | access to local variable sink46 | LocalDataFlow.cs:160:22:160:43 | call to method ToByte | -| LocalDataFlow.cs:161:15:161:20 | access to local variable sink47 | LocalDataFlow.cs:162:40:162:45 | access to local variable sink47 | -| LocalDataFlow.cs:162:13:162:46 | SSA def(sink49) | LocalDataFlow.cs:163:15:163:20 | access to local variable sink49 | -| LocalDataFlow.cs:162:22:162:46 | call to method Concat | LocalDataFlow.cs:162:13:162:46 | SSA def(sink49) | -| LocalDataFlow.cs:162:36:162:37 | "" | LocalDataFlow.cs:162:22:162:46 | call to method Concat | -| LocalDataFlow.cs:162:40:162:45 | (...) ... | LocalDataFlow.cs:162:22:162:46 | call to method Concat | -| LocalDataFlow.cs:162:40:162:45 | access to local variable sink47 | LocalDataFlow.cs:162:40:162:45 | (...) ... | -| LocalDataFlow.cs:163:15:163:20 | [post] access to local variable sink49 | LocalDataFlow.cs:164:34:164:39 | access to local variable sink49 | -| LocalDataFlow.cs:163:15:163:20 | access to local variable sink49 | LocalDataFlow.cs:164:34:164:39 | access to local variable sink49 | -| LocalDataFlow.cs:164:13:164:40 | SSA def(sink50) | LocalDataFlow.cs:165:15:165:20 | access to local variable sink50 | -| LocalDataFlow.cs:164:22:164:40 | call to method Copy | LocalDataFlow.cs:164:13:164:40 | SSA def(sink50) | -| LocalDataFlow.cs:164:34:164:39 | access to local variable sink49 | LocalDataFlow.cs:164:22:164:40 | call to method Copy | -| LocalDataFlow.cs:165:15:165:20 | [post] access to local variable sink50 | LocalDataFlow.cs:166:44:166:49 | access to local variable sink50 | -| LocalDataFlow.cs:165:15:165:20 | access to local variable sink50 | LocalDataFlow.cs:166:44:166:49 | access to local variable sink50 | -| LocalDataFlow.cs:166:13:166:54 | SSA def(sink51) | LocalDataFlow.cs:167:15:167:20 | access to local variable sink51 | -| LocalDataFlow.cs:166:22:166:54 | call to method Join | LocalDataFlow.cs:166:13:166:54 | SSA def(sink51) | -| LocalDataFlow.cs:166:34:166:37 | ", " | LocalDataFlow.cs:166:22:166:54 | call to method Join | -| LocalDataFlow.cs:166:40:166:41 | "" | LocalDataFlow.cs:166:22:166:54 | call to method Join | -| LocalDataFlow.cs:166:44:166:49 | access to local variable sink50 | LocalDataFlow.cs:166:22:166:54 | call to method Join | -| LocalDataFlow.cs:166:52:166:53 | "" | LocalDataFlow.cs:166:22:166:54 | call to method Join | -| LocalDataFlow.cs:167:15:167:20 | [post] access to local variable sink51 | LocalDataFlow.cs:168:35:168:40 | access to local variable sink51 | -| LocalDataFlow.cs:167:15:167:20 | access to local variable sink51 | LocalDataFlow.cs:168:35:168:40 | access to local variable sink51 | -| LocalDataFlow.cs:168:13:168:41 | SSA def(sink52) | LocalDataFlow.cs:169:15:169:20 | access to local variable sink52 | -| LocalDataFlow.cs:168:22:168:23 | "" | LocalDataFlow.cs:168:22:168:41 | call to method Insert | -| LocalDataFlow.cs:168:22:168:41 | call to method Insert | LocalDataFlow.cs:168:13:168:41 | SSA def(sink52) | -| LocalDataFlow.cs:168:35:168:40 | access to local variable sink51 | LocalDataFlow.cs:168:22:168:41 | call to method Insert | -| LocalDataFlow.cs:172:9:172:40 | SSA def(nonSink2) | LocalDataFlow.cs:173:15:173:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:172:20:172:40 | call to method Parse | LocalDataFlow.cs:172:9:172:40 | SSA def(nonSink2) | -| LocalDataFlow.cs:172:32:172:39 | [post] access to local variable nonSink0 | LocalDataFlow.cs:174:39:174:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:172:32:172:39 | access to local variable nonSink0 | LocalDataFlow.cs:172:20:172:40 | call to method Parse | -| LocalDataFlow.cs:172:32:172:39 | access to local variable nonSink0 | LocalDataFlow.cs:174:39:174:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:174:13:174:61 | SSA def(nonSink7) | LocalDataFlow.cs:175:15:175:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:174:24:174:61 | call to method TryParse | LocalDataFlow.cs:174:13:174:61 | SSA def(nonSink7) | -| LocalDataFlow.cs:174:39:174:46 | [post] access to local variable nonSink0 | LocalDataFlow.cs:176:20:176:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:174:39:174:46 | access to local variable nonSink0 | LocalDataFlow.cs:174:24:174:61 | call to method TryParse | -| LocalDataFlow.cs:174:39:174:46 | access to local variable nonSink0 | LocalDataFlow.cs:176:20:176:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:176:9:176:50 | SSA def(nonSink0) | LocalDataFlow.cs:177:15:177:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:176:20:176:27 | [post] access to local variable nonSink0 | LocalDataFlow.cs:176:42:176:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:176:20:176:27 | access to local variable nonSink0 | LocalDataFlow.cs:176:20:176:50 | call to method Replace | -| LocalDataFlow.cs:176:20:176:27 | access to local variable nonSink0 | LocalDataFlow.cs:176:42:176:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:176:20:176:50 | call to method Replace | LocalDataFlow.cs:176:9:176:50 | SSA def(nonSink0) | -| LocalDataFlow.cs:176:42:176:49 | access to local variable nonSink0 | LocalDataFlow.cs:176:20:176:50 | call to method Replace | -| LocalDataFlow.cs:177:15:177:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:178:34:178:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:177:15:177:22 | access to local variable nonSink0 | LocalDataFlow.cs:178:34:178:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:178:9:178:52 | SSA def(nonSink0) | LocalDataFlow.cs:179:15:179:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:178:20:178:52 | call to method Format | LocalDataFlow.cs:178:9:178:52 | SSA def(nonSink0) | -| LocalDataFlow.cs:178:34:178:41 | [post] access to local variable nonSink0 | LocalDataFlow.cs:178:44:178:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:178:34:178:41 | access to local variable nonSink0 | LocalDataFlow.cs:178:20:178:52 | call to method Format | -| LocalDataFlow.cs:178:34:178:41 | access to local variable nonSink0 | LocalDataFlow.cs:178:44:178:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:178:44:178:51 | access to local variable nonSink0 | LocalDataFlow.cs:178:20:178:52 | call to method Format | -| LocalDataFlow.cs:179:15:179:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:180:31:180:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:179:15:179:22 | access to local variable nonSink0 | LocalDataFlow.cs:180:31:180:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:180:9:180:39 | SSA def(nonSink7) | LocalDataFlow.cs:181:15:181:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:180:20:180:39 | call to method Parse | LocalDataFlow.cs:180:9:180:39 | SSA def(nonSink7) | -| LocalDataFlow.cs:180:31:180:38 | [post] access to local variable nonSink0 | LocalDataFlow.cs:182:34:182:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:180:31:180:38 | access to local variable nonSink0 | LocalDataFlow.cs:180:20:180:39 | call to method Parse | -| LocalDataFlow.cs:180:31:180:38 | access to local variable nonSink0 | LocalDataFlow.cs:182:34:182:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:182:9:182:57 | SSA def(nonSink7) | LocalDataFlow.cs:183:15:183:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:182:20:182:57 | call to method TryParse | LocalDataFlow.cs:182:9:182:57 | SSA def(nonSink7) | -| LocalDataFlow.cs:182:34:182:41 | access to local variable nonSink0 | LocalDataFlow.cs:182:20:182:57 | call to method TryParse | -| LocalDataFlow.cs:183:15:183:22 | access to local variable nonSink7 | LocalDataFlow.cs:184:40:184:47 | access to local variable nonSink7 | -| LocalDataFlow.cs:184:13:184:48 | SSA def(nonSink14) | LocalDataFlow.cs:185:15:185:23 | access to local variable nonSink14 | -| LocalDataFlow.cs:184:25:184:48 | call to method ToByte | LocalDataFlow.cs:184:13:184:48 | SSA def(nonSink14) | -| LocalDataFlow.cs:184:40:184:47 | access to local variable nonSink7 | LocalDataFlow.cs:184:25:184:48 | call to method ToByte | -| LocalDataFlow.cs:184:40:184:47 | access to local variable nonSink7 | LocalDataFlow.cs:186:38:186:45 | access to local variable nonSink7 | -| LocalDataFlow.cs:186:9:186:46 | SSA def(nonSink0) | LocalDataFlow.cs:187:15:187:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:186:20:186:46 | call to method Concat | LocalDataFlow.cs:186:9:186:46 | SSA def(nonSink0) | -| LocalDataFlow.cs:186:34:186:35 | "" | LocalDataFlow.cs:186:20:186:46 | call to method Concat | -| LocalDataFlow.cs:186:38:186:45 | (...) ... | LocalDataFlow.cs:186:20:186:46 | call to method Concat | -| LocalDataFlow.cs:186:38:186:45 | access to local variable nonSink7 | LocalDataFlow.cs:186:38:186:45 | (...) ... | -| LocalDataFlow.cs:187:15:187:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:188:32:188:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:187:15:187:22 | access to local variable nonSink0 | LocalDataFlow.cs:188:32:188:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:188:9:188:40 | SSA def(nonSink0) | LocalDataFlow.cs:189:15:189:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:188:20:188:40 | call to method Copy | LocalDataFlow.cs:188:9:188:40 | SSA def(nonSink0) | -| LocalDataFlow.cs:188:32:188:39 | access to local variable nonSink0 | LocalDataFlow.cs:188:20:188:40 | call to method Copy | -| LocalDataFlow.cs:189:15:189:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:190:42:190:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:189:15:189:22 | access to local variable nonSink0 | LocalDataFlow.cs:190:42:190:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:190:9:190:54 | SSA def(nonSink0) | LocalDataFlow.cs:191:15:191:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:190:20:190:54 | call to method Join | LocalDataFlow.cs:190:9:190:54 | SSA def(nonSink0) | -| LocalDataFlow.cs:190:32:190:35 | ", " | LocalDataFlow.cs:190:20:190:54 | call to method Join | -| LocalDataFlow.cs:190:38:190:39 | "" | LocalDataFlow.cs:190:20:190:54 | call to method Join | -| LocalDataFlow.cs:190:42:190:49 | access to local variable nonSink0 | LocalDataFlow.cs:190:20:190:54 | call to method Join | -| LocalDataFlow.cs:190:52:190:53 | "" | LocalDataFlow.cs:190:20:190:54 | call to method Join | -| LocalDataFlow.cs:191:15:191:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:192:33:192:40 | access to local variable nonSink0 | -| LocalDataFlow.cs:191:15:191:22 | access to local variable nonSink0 | LocalDataFlow.cs:192:33:192:40 | access to local variable nonSink0 | -| LocalDataFlow.cs:192:9:192:41 | SSA def(nonSink0) | LocalDataFlow.cs:193:15:193:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:192:20:192:21 | "" | LocalDataFlow.cs:192:20:192:41 | call to method Insert | -| LocalDataFlow.cs:192:20:192:41 | call to method Insert | LocalDataFlow.cs:192:9:192:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:192:33:192:40 | access to local variable nonSink0 | LocalDataFlow.cs:192:20:192:41 | call to method Insert | -| LocalDataFlow.cs:196:13:196:32 | SSA def(sink20) | LocalDataFlow.cs:197:15:197:20 | access to local variable sink20 | -| LocalDataFlow.cs:196:22:196:27 | access to local variable sink15 | LocalDataFlow.cs:196:22:196:32 | ... > ... | -| LocalDataFlow.cs:196:22:196:32 | ... > ... | LocalDataFlow.cs:196:13:196:32 | SSA def(sink20) | -| LocalDataFlow.cs:197:15:197:20 | access to local variable sink20 | LocalDataFlow.cs:226:22:226:27 | access to local variable sink20 | -| LocalDataFlow.cs:198:13:198:40 | SSA def(sink21) | LocalDataFlow.cs:199:15:199:20 | access to local variable sink21 | -| LocalDataFlow.cs:198:22:198:26 | access to local variable sink9 | LocalDataFlow.cs:198:22:198:40 | call to method Equals | -| LocalDataFlow.cs:198:22:198:40 | call to method Equals | LocalDataFlow.cs:198:13:198:40 | SSA def(sink21) | -| LocalDataFlow.cs:200:13:200:45 | SSA def(sink22) | LocalDataFlow.cs:201:15:201:20 | access to local variable sink22 | -| LocalDataFlow.cs:200:22:200:26 | [post] access to local variable sink8 | LocalDataFlow.cs:206:20:206:24 | access to local variable sink8 | -| LocalDataFlow.cs:200:22:200:26 | access to local variable sink8 | LocalDataFlow.cs:200:22:200:45 | call to method Equals | -| LocalDataFlow.cs:200:22:200:26 | access to local variable sink8 | LocalDataFlow.cs:206:20:206:24 | access to local variable sink8 | -| LocalDataFlow.cs:200:22:200:45 | call to method Equals | LocalDataFlow.cs:200:13:200:45 | SSA def(sink22) | -| LocalDataFlow.cs:200:43:200:44 | 41 | LocalDataFlow.cs:200:35:200:44 | (...) ... | -| LocalDataFlow.cs:204:9:204:38 | SSA def(nonSink7) | LocalDataFlow.cs:205:15:205:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:204:20:204:24 | [post] access to local variable sink0 | LocalDataFlow.cs:411:30:411:34 | access to local variable sink0 | -| LocalDataFlow.cs:204:20:204:24 | access to local variable sink0 | LocalDataFlow.cs:411:30:411:34 | access to local variable sink0 | -| LocalDataFlow.cs:204:20:204:38 | call to method Equals | LocalDataFlow.cs:204:9:204:38 | SSA def(nonSink7) | -| LocalDataFlow.cs:204:33:204:37 | [post] access to local variable sink1 | LocalDataFlow.cs:320:22:320:26 | access to local variable sink1 | -| LocalDataFlow.cs:204:33:204:37 | access to local variable sink1 | LocalDataFlow.cs:320:22:320:26 | access to local variable sink1 | -| LocalDataFlow.cs:206:9:206:41 | SSA def(nonSink7) | LocalDataFlow.cs:207:15:207:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:206:20:206:41 | call to method Equals | LocalDataFlow.cs:206:9:206:41 | SSA def(nonSink7) | -| LocalDataFlow.cs:207:15:207:22 | access to local variable nonSink7 | LocalDataFlow.cs:230:20:230:27 | access to local variable nonSink7 | -| LocalDataFlow.cs:210:13:210:31 | SSA def(sink23) | LocalDataFlow.cs:211:15:211:20 | access to local variable sink23 | -| LocalDataFlow.cs:210:22:210:27 | access to local variable sink11 | LocalDataFlow.cs:210:22:210:31 | access to indexer | -| LocalDataFlow.cs:210:22:210:31 | access to indexer | LocalDataFlow.cs:210:13:210:31 | SSA def(sink23) | -| LocalDataFlow.cs:211:15:211:20 | [post] access to local variable sink23 | LocalDataFlow.cs:234:37:234:42 | access to local variable sink23 | -| LocalDataFlow.cs:211:15:211:20 | access to local variable sink23 | LocalDataFlow.cs:234:37:234:42 | access to local variable sink23 | -| LocalDataFlow.cs:214:9:214:31 | SSA def(nonSink0) | LocalDataFlow.cs:215:15:215:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:214:20:214:27 | [post] access to local variable nonSink1 | LocalDataFlow.cs:328:9:328:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink1 | LocalDataFlow.cs:214:20:214:31 | access to indexer | -| LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink1 | LocalDataFlow.cs:328:9:328:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:214:20:214:31 | access to indexer | LocalDataFlow.cs:214:9:214:31 | SSA def(nonSink0) | -| LocalDataFlow.cs:215:15:215:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:246:39:246:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:215:15:215:22 | access to local variable nonSink0 | LocalDataFlow.cs:246:39:246:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:218:13:218:30 | SSA def(sink24) | LocalDataFlow.cs:219:15:219:20 | access to local variable sink24 | -| LocalDataFlow.cs:218:22:218:27 | access to local variable sink10 | LocalDataFlow.cs:218:22:218:30 | access to array element | -| LocalDataFlow.cs:218:22:218:27 | access to local variable sink10 | LocalDataFlow.cs:363:32:363:37 | access to local variable sink10 | -| LocalDataFlow.cs:218:22:218:30 | access to array element | LocalDataFlow.cs:218:13:218:30 | SSA def(sink24) | -| LocalDataFlow.cs:222:9:222:30 | SSA def(nonSink3) | LocalDataFlow.cs:223:15:223:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:222:20:222:27 | access to local variable nonSink4 | LocalDataFlow.cs:222:20:222:30 | access to array element | -| LocalDataFlow.cs:222:20:222:27 | access to local variable nonSink4 | LocalDataFlow.cs:377:35:377:42 | access to local variable nonSink4 | -| LocalDataFlow.cs:222:20:222:30 | access to array element | LocalDataFlow.cs:222:9:222:30 | SSA def(nonSink3) | -| LocalDataFlow.cs:226:13:226:36 | SSA def(sink25) | LocalDataFlow.cs:227:15:227:20 | access to local variable sink25 | -| LocalDataFlow.cs:226:22:226:27 | access to local variable sink20 | LocalDataFlow.cs:226:22:226:36 | ... \|\| ... | -| LocalDataFlow.cs:226:22:226:36 | ... \|\| ... | LocalDataFlow.cs:226:13:226:36 | SSA def(sink25) | -| LocalDataFlow.cs:226:32:226:36 | false | LocalDataFlow.cs:226:22:226:36 | ... \|\| ... | -| LocalDataFlow.cs:230:9:230:36 | SSA def(nonSink7) | LocalDataFlow.cs:231:15:231:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:230:20:230:27 | access to local variable nonSink7 | LocalDataFlow.cs:230:20:230:36 | ... \|\| ... | -| LocalDataFlow.cs:230:20:230:36 | ... \|\| ... | LocalDataFlow.cs:230:9:230:36 | SSA def(nonSink7) | -| LocalDataFlow.cs:230:32:230:36 | false | LocalDataFlow.cs:230:20:230:36 | ... \|\| ... | -| LocalDataFlow.cs:234:13:234:43 | SSA def(sink26) | LocalDataFlow.cs:235:15:235:20 | access to local variable sink26 | -| LocalDataFlow.cs:234:22:234:43 | object creation of type Uri | LocalDataFlow.cs:234:13:234:43 | SSA def(sink26) | -| LocalDataFlow.cs:234:37:234:42 | access to local variable sink23 | LocalDataFlow.cs:234:22:234:43 | object creation of type Uri | -| LocalDataFlow.cs:235:15:235:20 | [post] access to local variable sink26 | LocalDataFlow.cs:236:22:236:27 | access to local variable sink26 | -| LocalDataFlow.cs:235:15:235:20 | access to local variable sink26 | LocalDataFlow.cs:236:22:236:27 | access to local variable sink26 | -| LocalDataFlow.cs:236:13:236:38 | SSA def(sink27) | LocalDataFlow.cs:237:15:237:20 | access to local variable sink27 | -| LocalDataFlow.cs:236:22:236:27 | [post] access to local variable sink26 | LocalDataFlow.cs:238:22:238:27 | access to local variable sink26 | -| LocalDataFlow.cs:236:22:236:27 | access to local variable sink26 | LocalDataFlow.cs:236:22:236:38 | call to method ToString | -| LocalDataFlow.cs:236:22:236:27 | access to local variable sink26 | LocalDataFlow.cs:238:22:238:27 | access to local variable sink26 | -| LocalDataFlow.cs:236:22:236:38 | call to method ToString | LocalDataFlow.cs:236:13:236:38 | SSA def(sink27) | -| LocalDataFlow.cs:238:13:238:40 | SSA def(sink28) | LocalDataFlow.cs:239:15:239:20 | access to local variable sink28 | -| LocalDataFlow.cs:238:22:238:27 | [post] access to local variable sink26 | LocalDataFlow.cs:240:22:240:27 | access to local variable sink26 | -| LocalDataFlow.cs:238:22:238:27 | access to local variable sink26 | LocalDataFlow.cs:238:22:238:40 | access to property PathAndQuery | -| LocalDataFlow.cs:238:22:238:27 | access to local variable sink26 | LocalDataFlow.cs:240:22:240:27 | access to local variable sink26 | -| LocalDataFlow.cs:238:22:238:40 | access to property PathAndQuery | LocalDataFlow.cs:238:13:238:40 | SSA def(sink28) | -| LocalDataFlow.cs:240:13:240:33 | SSA def(sink29) | LocalDataFlow.cs:241:15:241:20 | access to local variable sink29 | -| LocalDataFlow.cs:240:22:240:27 | [post] access to local variable sink26 | LocalDataFlow.cs:242:22:242:27 | access to local variable sink26 | -| LocalDataFlow.cs:240:22:240:27 | access to local variable sink26 | LocalDataFlow.cs:240:22:240:33 | access to property Query | -| LocalDataFlow.cs:240:22:240:27 | access to local variable sink26 | LocalDataFlow.cs:242:22:242:27 | access to local variable sink26 | -| LocalDataFlow.cs:240:22:240:33 | access to property Query | LocalDataFlow.cs:240:13:240:33 | SSA def(sink29) | -| LocalDataFlow.cs:242:13:242:42 | SSA def(sink30) | LocalDataFlow.cs:243:15:243:20 | access to local variable sink30 | -| LocalDataFlow.cs:242:22:242:27 | access to local variable sink26 | LocalDataFlow.cs:242:22:242:42 | access to property OriginalString | -| LocalDataFlow.cs:242:22:242:42 | access to property OriginalString | LocalDataFlow.cs:242:13:242:42 | SSA def(sink30) | -| LocalDataFlow.cs:243:15:243:20 | [post] access to local variable sink30 | LocalDataFlow.cs:258:49:258:54 | access to local variable sink30 | -| LocalDataFlow.cs:243:15:243:20 | access to local variable sink30 | LocalDataFlow.cs:258:49:258:54 | access to local variable sink30 | -| LocalDataFlow.cs:246:13:246:47 | SSA def(nonSink8) | LocalDataFlow.cs:247:15:247:22 | access to local variable nonSink8 | -| LocalDataFlow.cs:246:24:246:47 | object creation of type Uri | LocalDataFlow.cs:246:13:246:47 | SSA def(nonSink8) | -| LocalDataFlow.cs:246:39:246:46 | access to local variable nonSink0 | LocalDataFlow.cs:246:24:246:47 | object creation of type Uri | -| LocalDataFlow.cs:247:15:247:22 | [post] access to local variable nonSink8 | LocalDataFlow.cs:248:20:248:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:247:15:247:22 | access to local variable nonSink8 | LocalDataFlow.cs:248:20:248:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:248:9:248:38 | SSA def(nonSink0) | LocalDataFlow.cs:249:15:249:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:248:20:248:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:250:20:250:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:248:20:248:27 | access to local variable nonSink8 | LocalDataFlow.cs:248:20:248:38 | call to method ToString | -| LocalDataFlow.cs:248:20:248:27 | access to local variable nonSink8 | LocalDataFlow.cs:250:20:250:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:248:20:248:38 | call to method ToString | LocalDataFlow.cs:248:9:248:38 | SSA def(nonSink0) | -| LocalDataFlow.cs:250:9:250:40 | SSA def(nonSink0) | LocalDataFlow.cs:251:15:251:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:250:20:250:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:252:20:252:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:250:20:250:27 | access to local variable nonSink8 | LocalDataFlow.cs:250:20:250:40 | access to property PathAndQuery | -| LocalDataFlow.cs:250:20:250:27 | access to local variable nonSink8 | LocalDataFlow.cs:252:20:252:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:250:20:250:40 | access to property PathAndQuery | LocalDataFlow.cs:250:9:250:40 | SSA def(nonSink0) | -| LocalDataFlow.cs:252:9:252:33 | SSA def(nonSink0) | LocalDataFlow.cs:253:15:253:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:252:20:252:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:254:20:254:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:252:20:252:27 | access to local variable nonSink8 | LocalDataFlow.cs:252:20:252:33 | access to property Query | -| LocalDataFlow.cs:252:20:252:27 | access to local variable nonSink8 | LocalDataFlow.cs:254:20:254:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:252:20:252:33 | access to property Query | LocalDataFlow.cs:252:9:252:33 | SSA def(nonSink0) | -| LocalDataFlow.cs:254:9:254:42 | SSA def(nonSink0) | LocalDataFlow.cs:255:15:255:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:254:20:254:27 | access to local variable nonSink8 | LocalDataFlow.cs:254:20:254:42 | access to property OriginalString | -| LocalDataFlow.cs:254:20:254:42 | access to property OriginalString | LocalDataFlow.cs:254:9:254:42 | SSA def(nonSink0) | -| LocalDataFlow.cs:255:15:255:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:264:51:264:58 | access to local variable nonSink0 | -| LocalDataFlow.cs:255:15:255:22 | access to local variable nonSink0 | LocalDataFlow.cs:264:51:264:58 | access to local variable nonSink0 | -| LocalDataFlow.cs:258:13:258:55 | SSA def(sink31) | LocalDataFlow.cs:259:15:259:20 | access to local variable sink31 | -| LocalDataFlow.cs:258:22:258:55 | object creation of type StringReader | LocalDataFlow.cs:258:13:258:55 | SSA def(sink31) | -| LocalDataFlow.cs:258:49:258:54 | access to local variable sink30 | LocalDataFlow.cs:258:22:258:55 | object creation of type StringReader | -| LocalDataFlow.cs:259:15:259:20 | [post] access to local variable sink31 | LocalDataFlow.cs:260:22:260:27 | access to local variable sink31 | -| LocalDataFlow.cs:259:15:259:20 | access to local variable sink31 | LocalDataFlow.cs:260:22:260:27 | access to local variable sink31 | -| LocalDataFlow.cs:260:13:260:39 | SSA def(sink32) | LocalDataFlow.cs:261:15:261:20 | access to local variable sink32 | -| LocalDataFlow.cs:260:22:260:27 | access to local variable sink31 | LocalDataFlow.cs:260:22:260:39 | call to method ReadToEnd | -| LocalDataFlow.cs:260:22:260:39 | call to method ReadToEnd | LocalDataFlow.cs:260:13:260:39 | SSA def(sink32) | -| LocalDataFlow.cs:261:15:261:20 | [post] access to local variable sink32 | LocalDataFlow.cs:270:30:270:35 | access to local variable sink32 | -| LocalDataFlow.cs:261:15:261:20 | access to local variable sink32 | LocalDataFlow.cs:270:30:270:35 | access to local variable sink32 | -| LocalDataFlow.cs:264:13:264:59 | SSA def(nonSink9) | LocalDataFlow.cs:265:15:265:22 | access to local variable nonSink9 | -| LocalDataFlow.cs:264:24:264:59 | object creation of type StringReader | LocalDataFlow.cs:264:13:264:59 | SSA def(nonSink9) | -| LocalDataFlow.cs:264:51:264:58 | access to local variable nonSink0 | LocalDataFlow.cs:264:24:264:59 | object creation of type StringReader | -| LocalDataFlow.cs:265:15:265:22 | [post] access to local variable nonSink9 | LocalDataFlow.cs:266:20:266:27 | access to local variable nonSink9 | -| LocalDataFlow.cs:265:15:265:22 | access to local variable nonSink9 | LocalDataFlow.cs:266:20:266:27 | access to local variable nonSink9 | -| LocalDataFlow.cs:266:9:266:39 | SSA def(nonSink0) | LocalDataFlow.cs:267:15:267:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:266:20:266:27 | access to local variable nonSink9 | LocalDataFlow.cs:266:20:266:39 | call to method ReadToEnd | -| LocalDataFlow.cs:266:20:266:39 | call to method ReadToEnd | LocalDataFlow.cs:266:9:266:39 | SSA def(nonSink0) | -| LocalDataFlow.cs:267:15:267:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:276:28:276:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:267:15:267:22 | access to local variable nonSink0 | LocalDataFlow.cs:276:28:276:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:270:13:270:127 | SSA def(sink33) | LocalDataFlow.cs:271:15:271:20 | access to local variable sink33 | -| LocalDataFlow.cs:270:22:270:127 | (...) ... | LocalDataFlow.cs:270:13:270:127 | SSA def(sink33) | -| LocalDataFlow.cs:270:30:270:35 | access to local variable sink32 | LocalDataFlow.cs:270:30:270:48 | call to method Substring | -| LocalDataFlow.cs:270:30:270:48 | call to method Substring | LocalDataFlow.cs:270:30:270:67 | call to method ToLowerInvariant | -| LocalDataFlow.cs:270:30:270:67 | call to method ToLowerInvariant | LocalDataFlow.cs:270:30:270:77 | call to method ToUpper | -| LocalDataFlow.cs:270:30:270:77 | call to method ToUpper | LocalDataFlow.cs:270:30:270:87 | call to method Trim | -| LocalDataFlow.cs:270:30:270:87 | call to method Trim | LocalDataFlow.cs:270:30:270:105 | call to method Replace | -| LocalDataFlow.cs:270:30:270:105 | call to method Replace | LocalDataFlow.cs:270:30:270:119 | call to method Insert | -| LocalDataFlow.cs:270:30:270:119 | call to method Insert | LocalDataFlow.cs:270:30:270:127 | call to method Clone | -| LocalDataFlow.cs:270:30:270:127 | call to method Clone | LocalDataFlow.cs:270:22:270:127 | (...) ... | -| LocalDataFlow.cs:270:102:270:104 | "b" | LocalDataFlow.cs:270:30:270:105 | call to method Replace | -| LocalDataFlow.cs:270:117:270:118 | "" | LocalDataFlow.cs:270:30:270:119 | call to method Insert | -| LocalDataFlow.cs:271:15:271:20 | [post] access to local variable sink33 | LocalDataFlow.cs:272:22:272:27 | access to local variable sink33 | -| LocalDataFlow.cs:271:15:271:20 | access to local variable sink33 | LocalDataFlow.cs:272:22:272:27 | access to local variable sink33 | -| LocalDataFlow.cs:272:13:272:63 | SSA def(sink48) | LocalDataFlow.cs:273:15:273:20 | access to local variable sink48 | -| LocalDataFlow.cs:272:22:272:27 | [post] access to local variable sink33 | LocalDataFlow.cs:282:40:282:45 | access to local variable sink33 | -| LocalDataFlow.cs:272:22:272:27 | access to local variable sink33 | LocalDataFlow.cs:272:22:272:39 | call to method Normalize | -| LocalDataFlow.cs:272:22:272:27 | access to local variable sink33 | LocalDataFlow.cs:282:40:282:45 | access to local variable sink33 | -| LocalDataFlow.cs:272:22:272:39 | call to method Normalize | LocalDataFlow.cs:272:22:272:52 | call to method Remove | -| LocalDataFlow.cs:272:22:272:52 | call to method Remove | LocalDataFlow.cs:272:22:272:63 | call to method Split | -| LocalDataFlow.cs:272:22:272:63 | call to method Split | LocalDataFlow.cs:272:13:272:63 | SSA def(sink48) | -| LocalDataFlow.cs:276:9:276:127 | SSA def(nonSink0) | LocalDataFlow.cs:277:15:277:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:276:20:276:127 | (...) ... | LocalDataFlow.cs:276:9:276:127 | SSA def(nonSink0) | -| LocalDataFlow.cs:276:28:276:35 | access to local variable nonSink0 | LocalDataFlow.cs:276:28:276:48 | call to method Substring | -| LocalDataFlow.cs:276:28:276:48 | call to method Substring | LocalDataFlow.cs:276:28:276:67 | call to method ToLowerInvariant | -| LocalDataFlow.cs:276:28:276:67 | call to method ToLowerInvariant | LocalDataFlow.cs:276:28:276:77 | call to method ToUpper | -| LocalDataFlow.cs:276:28:276:77 | call to method ToUpper | LocalDataFlow.cs:276:28:276:87 | call to method Trim | -| LocalDataFlow.cs:276:28:276:87 | call to method Trim | LocalDataFlow.cs:276:28:276:105 | call to method Replace | -| LocalDataFlow.cs:276:28:276:105 | call to method Replace | LocalDataFlow.cs:276:28:276:119 | call to method Insert | -| LocalDataFlow.cs:276:28:276:119 | call to method Insert | LocalDataFlow.cs:276:28:276:127 | call to method Clone | -| LocalDataFlow.cs:276:28:276:127 | call to method Clone | LocalDataFlow.cs:276:20:276:127 | (...) ... | -| LocalDataFlow.cs:276:102:276:104 | "b" | LocalDataFlow.cs:276:28:276:105 | call to method Replace | -| LocalDataFlow.cs:276:117:276:118 | "" | LocalDataFlow.cs:276:28:276:119 | call to method Insert | -| LocalDataFlow.cs:277:15:277:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:278:25:278:32 | access to local variable nonSink0 | -| LocalDataFlow.cs:277:15:277:22 | access to local variable nonSink0 | LocalDataFlow.cs:278:25:278:32 | access to local variable nonSink0 | -| LocalDataFlow.cs:278:13:278:68 | SSA def(nonSink15) | LocalDataFlow.cs:279:15:279:23 | access to local variable nonSink15 | -| LocalDataFlow.cs:278:25:278:32 | [post] access to local variable nonSink0 | LocalDataFlow.cs:291:43:291:50 | access to local variable nonSink0 | -| LocalDataFlow.cs:278:25:278:32 | access to local variable nonSink0 | LocalDataFlow.cs:278:25:278:44 | call to method Normalize | -| LocalDataFlow.cs:278:25:278:32 | access to local variable nonSink0 | LocalDataFlow.cs:291:43:291:50 | access to local variable nonSink0 | -| LocalDataFlow.cs:278:25:278:44 | call to method Normalize | LocalDataFlow.cs:278:25:278:57 | call to method Remove | -| LocalDataFlow.cs:278:25:278:57 | call to method Remove | LocalDataFlow.cs:278:25:278:68 | call to method Split | -| LocalDataFlow.cs:278:25:278:68 | call to method Split | LocalDataFlow.cs:278:13:278:68 | SSA def(nonSink15) | -| LocalDataFlow.cs:282:13:282:46 | SSA def(sink34) | LocalDataFlow.cs:283:15:283:20 | access to local variable sink34 | -| LocalDataFlow.cs:282:22:282:46 | object creation of type StringBuilder | LocalDataFlow.cs:282:13:282:46 | SSA def(sink34) | -| LocalDataFlow.cs:282:40:282:45 | access to local variable sink33 | LocalDataFlow.cs:282:22:282:46 | object creation of type StringBuilder | -| LocalDataFlow.cs:283:15:283:20 | [post] access to local variable sink34 | LocalDataFlow.cs:284:22:284:27 | access to local variable sink34 | -| LocalDataFlow.cs:283:15:283:20 | access to local variable sink34 | LocalDataFlow.cs:284:22:284:27 | access to local variable sink34 | -| LocalDataFlow.cs:284:13:284:38 | SSA def(sink35) | LocalDataFlow.cs:285:15:285:20 | access to local variable sink35 | -| LocalDataFlow.cs:284:22:284:27 | access to local variable sink34 | LocalDataFlow.cs:284:22:284:38 | call to method ToString | -| LocalDataFlow.cs:284:22:284:38 | call to method ToString | LocalDataFlow.cs:284:13:284:38 | SSA def(sink35) | -| LocalDataFlow.cs:285:15:285:20 | [post] access to local variable sink35 | LocalDataFlow.cs:287:27:287:32 | access to local variable sink35 | -| LocalDataFlow.cs:285:15:285:20 | access to local variable sink35 | LocalDataFlow.cs:287:27:287:32 | access to local variable sink35 | -| LocalDataFlow.cs:286:13:286:42 | SSA def(sink36) | LocalDataFlow.cs:287:9:287:14 | access to local variable sink36 | -| LocalDataFlow.cs:286:22:286:42 | object creation of type StringBuilder | LocalDataFlow.cs:286:13:286:42 | SSA def(sink36) | -| LocalDataFlow.cs:286:40:286:41 | "" | LocalDataFlow.cs:286:22:286:42 | object creation of type StringBuilder | -| LocalDataFlow.cs:287:9:287:14 | [post] access to local variable sink36 | LocalDataFlow.cs:288:15:288:20 | access to local variable sink36 | -| LocalDataFlow.cs:287:9:287:14 | access to local variable sink36 | LocalDataFlow.cs:288:15:288:20 | access to local variable sink36 | -| LocalDataFlow.cs:287:27:287:32 | access to local variable sink35 | LocalDataFlow.cs:287:9:287:14 | access to local variable sink36 | -| LocalDataFlow.cs:291:13:291:51 | SSA def(nonSink10) | LocalDataFlow.cs:292:15:292:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:291:25:291:51 | object creation of type StringBuilder | LocalDataFlow.cs:291:13:291:51 | SSA def(nonSink10) | -| LocalDataFlow.cs:291:43:291:50 | access to local variable nonSink0 | LocalDataFlow.cs:291:25:291:51 | object creation of type StringBuilder | -| LocalDataFlow.cs:292:15:292:23 | [post] access to local variable nonSink10 | LocalDataFlow.cs:293:20:293:28 | access to local variable nonSink10 | -| LocalDataFlow.cs:292:15:292:23 | access to local variable nonSink10 | LocalDataFlow.cs:293:20:293:28 | access to local variable nonSink10 | -| LocalDataFlow.cs:293:9:293:39 | SSA def(nonSink0) | LocalDataFlow.cs:294:15:294:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:293:20:293:28 | [post] access to local variable nonSink10 | LocalDataFlow.cs:295:9:295:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:293:20:293:28 | access to local variable nonSink10 | LocalDataFlow.cs:293:20:293:39 | call to method ToString | -| LocalDataFlow.cs:293:20:293:28 | access to local variable nonSink10 | LocalDataFlow.cs:295:9:295:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:293:20:293:39 | call to method ToString | LocalDataFlow.cs:293:9:293:39 | SSA def(nonSink0) | -| LocalDataFlow.cs:294:15:294:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:295:30:295:37 | access to local variable nonSink0 | -| LocalDataFlow.cs:294:15:294:22 | access to local variable nonSink0 | LocalDataFlow.cs:295:30:295:37 | access to local variable nonSink0 | -| LocalDataFlow.cs:295:9:295:17 | [post] access to local variable nonSink10 | LocalDataFlow.cs:296:15:296:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:295:9:295:17 | access to local variable nonSink10 | LocalDataFlow.cs:296:15:296:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:295:30:295:37 | access to local variable nonSink0 | LocalDataFlow.cs:295:9:295:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:299:13:299:52 | SSA def(sink40) | LocalDataFlow.cs:300:15:300:20 | access to local variable sink40 | -| LocalDataFlow.cs:299:22:299:52 | object creation of type Lazy | LocalDataFlow.cs:299:13:299:52 | SSA def(sink40) | -| LocalDataFlow.cs:299:39:299:51 | [output] delegate creation of type Func | LocalDataFlow.cs:299:22:299:52 | object creation of type Lazy | -| LocalDataFlow.cs:299:39:299:51 | this access | LocalDataFlow.cs:309:42:309:57 | this access | -| LocalDataFlow.cs:300:15:300:20 | [post] access to local variable sink40 | LocalDataFlow.cs:301:22:301:27 | access to local variable sink40 | -| LocalDataFlow.cs:300:15:300:20 | access to local variable sink40 | LocalDataFlow.cs:301:22:301:27 | access to local variable sink40 | -| LocalDataFlow.cs:301:13:301:33 | SSA def(sink41) | LocalDataFlow.cs:302:15:302:20 | access to local variable sink41 | -| LocalDataFlow.cs:301:22:301:27 | access to local variable sink40 | LocalDataFlow.cs:301:22:301:33 | access to property Value | -| LocalDataFlow.cs:301:22:301:33 | access to property Value | LocalDataFlow.cs:301:13:301:33 | SSA def(sink41) | -| LocalDataFlow.cs:303:13:303:59 | SSA def(sink42) | LocalDataFlow.cs:304:15:304:20 | access to local variable sink42 | -| LocalDataFlow.cs:303:22:303:59 | object creation of type Lazy | LocalDataFlow.cs:303:13:303:59 | SSA def(sink42) | -| LocalDataFlow.cs:303:39:303:58 | [output] (...) => ... | LocalDataFlow.cs:303:22:303:59 | object creation of type Lazy | -| LocalDataFlow.cs:304:15:304:20 | [post] access to local variable sink42 | LocalDataFlow.cs:305:22:305:27 | access to local variable sink42 | -| LocalDataFlow.cs:304:15:304:20 | access to local variable sink42 | LocalDataFlow.cs:305:22:305:27 | access to local variable sink42 | -| LocalDataFlow.cs:305:13:305:33 | SSA def(sink43) | LocalDataFlow.cs:306:15:306:20 | access to local variable sink43 | -| LocalDataFlow.cs:305:22:305:27 | access to local variable sink42 | LocalDataFlow.cs:305:22:305:33 | access to property Value | -| LocalDataFlow.cs:305:22:305:33 | access to property Value | LocalDataFlow.cs:305:13:305:33 | SSA def(sink43) | -| LocalDataFlow.cs:309:13:309:58 | SSA def(nonSink12) | LocalDataFlow.cs:310:15:310:23 | access to local variable nonSink12 | -| LocalDataFlow.cs:309:25:309:58 | object creation of type Lazy | LocalDataFlow.cs:309:13:309:58 | SSA def(nonSink12) | -| LocalDataFlow.cs:309:42:309:57 | [output] delegate creation of type Func | LocalDataFlow.cs:309:25:309:58 | object creation of type Lazy | -| LocalDataFlow.cs:310:15:310:23 | [post] access to local variable nonSink12 | LocalDataFlow.cs:311:20:311:28 | access to local variable nonSink12 | -| LocalDataFlow.cs:310:15:310:23 | access to local variable nonSink12 | LocalDataFlow.cs:311:20:311:28 | access to local variable nonSink12 | -| LocalDataFlow.cs:311:9:311:34 | SSA def(nonSink0) | LocalDataFlow.cs:312:15:312:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:311:20:311:28 | access to local variable nonSink12 | LocalDataFlow.cs:311:20:311:34 | access to property Value | -| LocalDataFlow.cs:311:20:311:34 | access to property Value | LocalDataFlow.cs:311:9:311:34 | SSA def(nonSink0) | -| LocalDataFlow.cs:313:9:313:46 | SSA def(nonSink12) | LocalDataFlow.cs:314:15:314:23 | access to local variable nonSink12 | -| LocalDataFlow.cs:313:21:313:46 | object creation of type Lazy | LocalDataFlow.cs:313:9:313:46 | SSA def(nonSink12) | -| LocalDataFlow.cs:313:38:313:45 | [output] (...) => ... | LocalDataFlow.cs:313:21:313:46 | object creation of type Lazy | -| LocalDataFlow.cs:314:15:314:23 | [post] access to local variable nonSink12 | LocalDataFlow.cs:315:20:315:28 | access to local variable nonSink12 | -| LocalDataFlow.cs:314:15:314:23 | access to local variable nonSink12 | LocalDataFlow.cs:315:20:315:28 | access to local variable nonSink12 | -| LocalDataFlow.cs:315:9:315:34 | SSA def(nonSink0) | LocalDataFlow.cs:316:15:316:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:315:20:315:28 | access to local variable nonSink12 | LocalDataFlow.cs:315:20:315:34 | access to property Value | -| LocalDataFlow.cs:315:20:315:34 | access to property Value | LocalDataFlow.cs:315:9:315:34 | SSA def(nonSink0) | -| LocalDataFlow.cs:316:15:316:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:328:26:328:33 | access to local variable nonSink0 | -| LocalDataFlow.cs:316:15:316:22 | access to local variable nonSink0 | LocalDataFlow.cs:328:26:328:33 | access to local variable nonSink0 | -| LocalDataFlow.cs:319:13:319:49 | SSA def(sink3) | LocalDataFlow.cs:320:9:320:13 | access to local variable sink3 | -| LocalDataFlow.cs:319:21:319:49 | object creation of type Dictionary | LocalDataFlow.cs:319:13:319:49 | SSA def(sink3) | -| LocalDataFlow.cs:320:9:320:13 | [post] access to local variable sink3 | LocalDataFlow.cs:321:15:321:19 | access to local variable sink3 | -| LocalDataFlow.cs:320:9:320:13 | access to local variable sink3 | LocalDataFlow.cs:321:15:321:19 | access to local variable sink3 | -| LocalDataFlow.cs:320:22:320:26 | [post] access to local variable sink1 | LocalDataFlow.cs:329:22:329:26 | access to local variable sink1 | -| LocalDataFlow.cs:320:22:320:26 | access to local variable sink1 | LocalDataFlow.cs:320:9:320:13 | access to local variable sink3 | -| LocalDataFlow.cs:320:22:320:26 | access to local variable sink1 | LocalDataFlow.cs:329:22:329:26 | access to local variable sink1 | -| LocalDataFlow.cs:321:15:321:19 | [post] access to local variable sink3 | LocalDataFlow.cs:322:22:322:26 | access to local variable sink3 | -| LocalDataFlow.cs:321:15:321:19 | access to local variable sink3 | LocalDataFlow.cs:322:22:322:26 | access to local variable sink3 | -| LocalDataFlow.cs:322:13:322:33 | SSA def(sink12) | LocalDataFlow.cs:323:15:323:20 | access to local variable sink12 | -| LocalDataFlow.cs:322:22:322:26 | [post] access to local variable sink3 | LocalDataFlow.cs:369:57:369:61 | access to local variable sink3 | -| LocalDataFlow.cs:322:22:322:26 | access to local variable sink3 | LocalDataFlow.cs:322:22:322:33 | access to property Values | -| LocalDataFlow.cs:322:22:322:26 | access to local variable sink3 | LocalDataFlow.cs:369:57:369:61 | access to local variable sink3 | -| LocalDataFlow.cs:322:22:322:33 | access to property Values | LocalDataFlow.cs:322:13:322:33 | SSA def(sink12) | -| LocalDataFlow.cs:323:15:323:20 | [post] access to local variable sink12 | LocalDataFlow.cs:324:22:324:27 | access to local variable sink12 | -| LocalDataFlow.cs:323:15:323:20 | access to local variable sink12 | LocalDataFlow.cs:324:22:324:27 | access to local variable sink12 | -| LocalDataFlow.cs:324:13:324:37 | SSA def(sink13) | LocalDataFlow.cs:325:15:325:20 | access to local variable sink13 | -| LocalDataFlow.cs:324:22:324:27 | access to local variable sink12 | LocalDataFlow.cs:324:22:324:37 | call to method Reverse | -| LocalDataFlow.cs:324:22:324:37 | call to method Reverse | LocalDataFlow.cs:324:13:324:37 | SSA def(sink13) | -| LocalDataFlow.cs:328:9:328:16 | [post] access to local variable nonSink1 | LocalDataFlow.cs:329:9:329:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:328:9:328:16 | access to local variable nonSink1 | LocalDataFlow.cs:329:9:329:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:328:26:328:33 | access to local variable nonSink0 | LocalDataFlow.cs:328:9:328:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:329:9:329:16 | [post] access to local variable nonSink1 | LocalDataFlow.cs:330:15:330:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:329:9:329:16 | access to local variable nonSink1 | LocalDataFlow.cs:330:15:330:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:329:22:329:26 | [post] access to local variable sink1 | LocalDataFlow.cs:403:30:403:34 | access to local variable sink1 | -| LocalDataFlow.cs:329:22:329:26 | access to local variable sink1 | LocalDataFlow.cs:403:30:403:34 | access to local variable sink1 | -| LocalDataFlow.cs:329:29:329:30 | "" | LocalDataFlow.cs:329:9:329:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:330:15:330:22 | [post] access to local variable nonSink1 | LocalDataFlow.cs:331:24:331:31 | access to local variable nonSink1 | -| LocalDataFlow.cs:330:15:330:22 | access to local variable nonSink1 | LocalDataFlow.cs:331:24:331:31 | access to local variable nonSink1 | -| LocalDataFlow.cs:331:13:331:38 | SSA def(nonSink5) | LocalDataFlow.cs:332:15:332:22 | access to local variable nonSink5 | -| LocalDataFlow.cs:331:24:331:31 | [post] access to local variable nonSink1 | LocalDataFlow.cs:383:63:383:70 | access to local variable nonSink1 | -| LocalDataFlow.cs:331:24:331:31 | access to local variable nonSink1 | LocalDataFlow.cs:331:24:331:38 | access to property Values | -| LocalDataFlow.cs:331:24:331:31 | access to local variable nonSink1 | LocalDataFlow.cs:383:63:383:70 | access to local variable nonSink1 | -| LocalDataFlow.cs:331:24:331:38 | access to property Values | LocalDataFlow.cs:331:13:331:38 | SSA def(nonSink5) | -| LocalDataFlow.cs:332:15:332:22 | [post] access to local variable nonSink5 | LocalDataFlow.cs:333:24:333:31 | access to local variable nonSink5 | -| LocalDataFlow.cs:332:15:332:22 | access to local variable nonSink5 | LocalDataFlow.cs:333:24:333:31 | access to local variable nonSink5 | -| LocalDataFlow.cs:333:13:333:41 | SSA def(nonSink6) | LocalDataFlow.cs:334:15:334:22 | access to local variable nonSink6 | -| LocalDataFlow.cs:333:24:333:31 | access to local variable nonSink5 | LocalDataFlow.cs:333:24:333:41 | call to method Reverse | -| LocalDataFlow.cs:333:24:333:41 | call to method Reverse | LocalDataFlow.cs:333:13:333:41 | SSA def(nonSink6) | -| LocalDataFlow.cs:337:13:337:52 | SSA def(taintedDataContract) | LocalDataFlow.cs:338:22:338:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:337:13:337:52 | SSA qualifier def(taintedDataContract.AList) | LocalDataFlow.cs:340:22:340:46 | access to property AList | -| LocalDataFlow.cs:337:35:337:52 | object creation of type DataContract | LocalDataFlow.cs:337:13:337:52 | SSA def(taintedDataContract) | -| LocalDataFlow.cs:338:13:338:48 | SSA def(sink53) | LocalDataFlow.cs:339:15:339:20 | access to local variable sink53 | -| LocalDataFlow.cs:338:22:338:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:340:22:340:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:338:22:338:40 | access to local variable taintedDataContract | LocalDataFlow.cs:338:22:338:48 | access to property AString | -| LocalDataFlow.cs:338:22:338:40 | access to local variable taintedDataContract | LocalDataFlow.cs:340:22:340:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:338:22:338:48 | access to property AString | LocalDataFlow.cs:338:13:338:48 | SSA def(sink53) | -| LocalDataFlow.cs:340:13:340:57 | SSA def(sink54) | LocalDataFlow.cs:341:15:341:20 | access to local variable sink54 | -| LocalDataFlow.cs:340:22:340:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:347:20:347:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:340:22:340:40 | access to local variable taintedDataContract | LocalDataFlow.cs:340:22:340:46 | access to property AList | -| LocalDataFlow.cs:340:22:340:40 | access to local variable taintedDataContract | LocalDataFlow.cs:347:20:347:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:340:22:340:46 | [post] access to property AList | LocalDataFlow.cs:349:20:349:44 | access to property AList | -| LocalDataFlow.cs:340:22:340:46 | access to property AList | LocalDataFlow.cs:340:22:340:49 | access to indexer | -| LocalDataFlow.cs:340:22:340:46 | access to property AList | LocalDataFlow.cs:349:20:349:44 | access to property AList | -| LocalDataFlow.cs:340:22:340:49 | access to indexer | LocalDataFlow.cs:340:22:340:57 | access to property AString | -| LocalDataFlow.cs:340:22:340:57 | access to property AString | LocalDataFlow.cs:340:13:340:57 | SSA def(sink54) | -| LocalDataFlow.cs:344:13:344:55 | SSA def(nonTaintedDataContract) | LocalDataFlow.cs:345:20:345:41 | access to local variable nonTaintedDataContract | -| LocalDataFlow.cs:344:38:344:55 | object creation of type DataContract | LocalDataFlow.cs:344:13:344:55 | SSA def(nonTaintedDataContract) | -| LocalDataFlow.cs:345:9:345:49 | SSA def(nonSink0) | LocalDataFlow.cs:346:15:346:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:345:20:345:41 | access to local variable nonTaintedDataContract | LocalDataFlow.cs:345:20:345:49 | access to property AString | -| LocalDataFlow.cs:345:20:345:49 | access to property AString | LocalDataFlow.cs:345:9:345:49 | SSA def(nonSink0) | -| LocalDataFlow.cs:347:9:347:44 | SSA def(nonSink2) | LocalDataFlow.cs:348:15:348:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:347:20:347:38 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:349:20:349:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:347:20:347:38 | access to local variable taintedDataContract | LocalDataFlow.cs:349:20:349:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:347:20:347:44 | access to property AnInt | LocalDataFlow.cs:347:9:347:44 | SSA def(nonSink2) | -| LocalDataFlow.cs:349:9:349:53 | SSA def(nonSink2) | LocalDataFlow.cs:350:15:350:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:349:20:349:38 | access to local variable taintedDataContract | LocalDataFlow.cs:349:20:349:44 | access to property AList | -| LocalDataFlow.cs:349:20:349:44 | access to property AList | LocalDataFlow.cs:349:20:349:47 | access to indexer | -| LocalDataFlow.cs:349:20:349:53 | access to property AnInt | LocalDataFlow.cs:349:9:349:53 | SSA def(nonSink2) | -| LocalDataFlow.cs:353:17:353:37 | SSA def(taintedTextBox) | LocalDataFlow.cs:354:22:354:35 | access to local variable taintedTextBox | -| LocalDataFlow.cs:353:34:353:37 | null | LocalDataFlow.cs:353:17:353:37 | SSA def(taintedTextBox) | -| LocalDataFlow.cs:354:13:354:40 | SSA def(sink60) | LocalDataFlow.cs:355:15:355:20 | access to local variable sink60 | -| LocalDataFlow.cs:354:22:354:35 | access to local variable taintedTextBox | LocalDataFlow.cs:354:22:354:40 | access to property Text | -| LocalDataFlow.cs:354:22:354:40 | access to property Text | LocalDataFlow.cs:354:13:354:40 | SSA def(sink60) | -| LocalDataFlow.cs:358:17:358:40 | SSA def(nonTaintedTextBox) | LocalDataFlow.cs:359:20:359:36 | access to local variable nonTaintedTextBox | -| LocalDataFlow.cs:358:37:358:40 | null | LocalDataFlow.cs:358:17:358:40 | SSA def(nonTaintedTextBox) | -| LocalDataFlow.cs:359:9:359:41 | SSA def(nonSink0) | LocalDataFlow.cs:360:15:360:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:359:20:359:36 | access to local variable nonTaintedTextBox | LocalDataFlow.cs:359:20:359:41 | access to property Text | -| LocalDataFlow.cs:359:20:359:41 | access to property Text | LocalDataFlow.cs:359:9:359:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:363:22:363:27 | SSA def(sink61) | LocalDataFlow.cs:364:19:364:24 | access to local variable sink61 | -| LocalDataFlow.cs:363:32:363:37 | access to local variable sink10 | LocalDataFlow.cs:363:22:363:27 | SSA def(sink61) | -| LocalDataFlow.cs:363:32:363:37 | access to local variable sink10 | LocalDataFlow.cs:365:30:365:35 | access to local variable sink10 | -| LocalDataFlow.cs:365:21:365:51 | SSA def(sink62) | LocalDataFlow.cs:366:15:366:20 | access to local variable sink62 | -| LocalDataFlow.cs:365:30:365:35 | access to local variable sink10 | LocalDataFlow.cs:365:30:365:51 | call to method GetEnumerator | -| LocalDataFlow.cs:365:30:365:51 | call to method GetEnumerator | LocalDataFlow.cs:365:21:365:51 | SSA def(sink62) | -| LocalDataFlow.cs:366:15:366:20 | [post] access to local variable sink62 | LocalDataFlow.cs:367:22:367:27 | access to local variable sink62 | -| LocalDataFlow.cs:366:15:366:20 | access to local variable sink62 | LocalDataFlow.cs:367:22:367:27 | access to local variable sink62 | -| LocalDataFlow.cs:367:13:367:35 | SSA def(sink63) | LocalDataFlow.cs:368:15:368:20 | access to local variable sink63 | -| LocalDataFlow.cs:367:22:367:27 | access to local variable sink62 | LocalDataFlow.cs:367:22:367:35 | access to property Current | -| LocalDataFlow.cs:367:22:367:35 | access to property Current | LocalDataFlow.cs:367:13:367:35 | SSA def(sink63) | -| LocalDataFlow.cs:369:48:369:77 | SSA def(sink64) | LocalDataFlow.cs:370:15:370:20 | access to local variable sink64 | -| LocalDataFlow.cs:369:57:369:61 | access to local variable sink3 | LocalDataFlow.cs:369:57:369:77 | call to method GetEnumerator | -| LocalDataFlow.cs:369:57:369:77 | (...) ... | LocalDataFlow.cs:369:48:369:77 | SSA def(sink64) | -| LocalDataFlow.cs:369:57:369:77 | call to method GetEnumerator | LocalDataFlow.cs:369:57:369:77 | (...) ... | -| LocalDataFlow.cs:370:15:370:20 | [post] access to local variable sink64 | LocalDataFlow.cs:371:22:371:27 | access to local variable sink64 | -| LocalDataFlow.cs:370:15:370:20 | access to local variable sink64 | LocalDataFlow.cs:371:22:371:27 | access to local variable sink64 | -| LocalDataFlow.cs:371:13:371:35 | SSA def(sink65) | LocalDataFlow.cs:372:15:372:20 | access to local variable sink65 | -| LocalDataFlow.cs:371:22:371:27 | access to local variable sink64 | LocalDataFlow.cs:371:22:371:35 | access to property Current | -| LocalDataFlow.cs:371:22:371:35 | access to property Current | LocalDataFlow.cs:371:13:371:35 | SSA def(sink65) | -| LocalDataFlow.cs:372:15:372:20 | access to local variable sink65 | LocalDataFlow.cs:373:22:373:27 | access to local variable sink65 | -| LocalDataFlow.cs:373:13:373:33 | SSA def(sink66) | LocalDataFlow.cs:374:15:374:20 | access to local variable sink66 | -| LocalDataFlow.cs:373:22:373:27 | access to local variable sink65 | LocalDataFlow.cs:373:22:373:33 | access to property Value | -| LocalDataFlow.cs:373:22:373:33 | access to property Value | LocalDataFlow.cs:373:13:373:33 | SSA def(sink66) | -| LocalDataFlow.cs:377:22:377:30 | SSA def(nonSink17) | LocalDataFlow.cs:378:19:378:27 | access to local variable nonSink17 | -| LocalDataFlow.cs:377:35:377:42 | access to local variable nonSink4 | LocalDataFlow.cs:377:22:377:30 | SSA def(nonSink17) | -| LocalDataFlow.cs:377:35:377:42 | access to local variable nonSink4 | LocalDataFlow.cs:379:33:379:40 | access to local variable nonSink4 | -| LocalDataFlow.cs:379:21:379:56 | SSA def(nonSink18) | LocalDataFlow.cs:380:15:380:23 | access to local variable nonSink18 | -| LocalDataFlow.cs:379:33:379:40 | access to local variable nonSink4 | LocalDataFlow.cs:379:33:379:56 | call to method GetEnumerator | -| LocalDataFlow.cs:379:33:379:56 | call to method GetEnumerator | LocalDataFlow.cs:379:21:379:56 | SSA def(nonSink18) | -| LocalDataFlow.cs:380:15:380:23 | [post] access to local variable nonSink18 | LocalDataFlow.cs:381:20:381:28 | access to local variable nonSink18 | -| LocalDataFlow.cs:380:15:380:23 | access to local variable nonSink18 | LocalDataFlow.cs:381:20:381:28 | access to local variable nonSink18 | -| LocalDataFlow.cs:381:9:381:36 | SSA def(nonSink3) | LocalDataFlow.cs:382:15:382:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:381:20:381:28 | access to local variable nonSink18 | LocalDataFlow.cs:381:20:381:36 | access to property Current | -| LocalDataFlow.cs:381:20:381:36 | access to property Current | LocalDataFlow.cs:381:9:381:36 | SSA def(nonSink3) | -| LocalDataFlow.cs:383:51:383:86 | SSA def(nonSink19) | LocalDataFlow.cs:384:15:384:23 | access to local variable nonSink19 | -| LocalDataFlow.cs:383:63:383:70 | access to local variable nonSink1 | LocalDataFlow.cs:383:63:383:86 | call to method GetEnumerator | -| LocalDataFlow.cs:383:63:383:86 | (...) ... | LocalDataFlow.cs:383:51:383:86 | SSA def(nonSink19) | -| LocalDataFlow.cs:383:63:383:86 | call to method GetEnumerator | LocalDataFlow.cs:383:63:383:86 | (...) ... | -| LocalDataFlow.cs:384:15:384:23 | [post] access to local variable nonSink19 | LocalDataFlow.cs:385:25:385:33 | access to local variable nonSink19 | -| LocalDataFlow.cs:384:15:384:23 | access to local variable nonSink19 | LocalDataFlow.cs:385:25:385:33 | access to local variable nonSink19 | -| LocalDataFlow.cs:385:13:385:41 | SSA def(nonSink20) | LocalDataFlow.cs:386:15:386:23 | access to local variable nonSink20 | -| LocalDataFlow.cs:385:25:385:33 | access to local variable nonSink19 | LocalDataFlow.cs:385:25:385:41 | access to property Current | -| LocalDataFlow.cs:385:25:385:41 | access to property Current | LocalDataFlow.cs:385:13:385:41 | SSA def(nonSink20) | -| LocalDataFlow.cs:386:15:386:23 | access to local variable nonSink20 | LocalDataFlow.cs:387:20:387:28 | access to local variable nonSink20 | -| LocalDataFlow.cs:387:9:387:34 | SSA def(nonSink0) | LocalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:387:20:387:28 | access to local variable nonSink20 | LocalDataFlow.cs:387:20:387:34 | access to property Value | -| LocalDataFlow.cs:387:20:387:34 | access to property Value | LocalDataFlow.cs:387:9:387:34 | SSA def(nonSink0) | -| LocalDataFlow.cs:391:13:391:51 | SSA def(sink67) | LocalDataFlow.cs:392:15:392:20 | access to local variable sink67 | -| LocalDataFlow.cs:391:22:391:51 | call to method Run | LocalDataFlow.cs:391:13:391:51 | SSA def(sink67) | -| LocalDataFlow.cs:391:31:391:50 | [output] (...) => ... | LocalDataFlow.cs:391:22:391:51 | call to method Run | -| LocalDataFlow.cs:392:15:392:20 | [post] access to local variable sink67 | LocalDataFlow.cs:393:28:393:33 | access to local variable sink67 | -| LocalDataFlow.cs:392:15:392:20 | access to local variable sink67 | LocalDataFlow.cs:393:28:393:33 | access to local variable sink67 | -| LocalDataFlow.cs:393:13:393:33 | SSA def(sink68) | LocalDataFlow.cs:394:15:394:20 | access to local variable sink68 | -| LocalDataFlow.cs:393:22:393:33 | await ... | LocalDataFlow.cs:393:13:393:33 | SSA def(sink68) | -| LocalDataFlow.cs:393:28:393:33 | access to local variable sink67 | LocalDataFlow.cs:393:22:393:33 | await ... | -| LocalDataFlow.cs:397:13:397:42 | SSA def(nonSink21) | LocalDataFlow.cs:398:15:398:23 | access to local variable nonSink21 | -| LocalDataFlow.cs:397:25:397:42 | call to method Run | LocalDataFlow.cs:397:13:397:42 | SSA def(nonSink21) | -| LocalDataFlow.cs:397:34:397:41 | [output] (...) => ... | LocalDataFlow.cs:397:25:397:42 | call to method Run | -| LocalDataFlow.cs:398:15:398:23 | [post] access to local variable nonSink21 | LocalDataFlow.cs:399:26:399:34 | access to local variable nonSink21 | -| LocalDataFlow.cs:398:15:398:23 | access to local variable nonSink21 | LocalDataFlow.cs:399:26:399:34 | access to local variable nonSink21 | -| LocalDataFlow.cs:399:9:399:34 | SSA def(nonSink0) | LocalDataFlow.cs:400:15:400:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:399:20:399:34 | await ... | LocalDataFlow.cs:399:9:399:34 | SSA def(nonSink0) | -| LocalDataFlow.cs:399:26:399:34 | access to local variable nonSink21 | LocalDataFlow.cs:399:20:399:34 | await ... | -| LocalDataFlow.cs:400:15:400:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:407:28:407:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:400:15:400:22 | access to local variable nonSink0 | LocalDataFlow.cs:407:28:407:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:403:13:403:36 | SSA def(sink69) | LocalDataFlow.cs:404:15:404:20 | access to local variable sink69 | -| LocalDataFlow.cs:403:22:403:36 | $"..." | LocalDataFlow.cs:403:13:403:36 | SSA def(sink69) | -| LocalDataFlow.cs:403:24:403:28 | "test " | LocalDataFlow.cs:403:22:403:36 | $"..." | -| LocalDataFlow.cs:403:30:403:34 | access to local variable sink1 | LocalDataFlow.cs:403:22:403:36 | $"..." | -| LocalDataFlow.cs:407:9:407:37 | SSA def(nonSink0) | LocalDataFlow.cs:408:15:408:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:407:20:407:37 | $"..." | LocalDataFlow.cs:407:9:407:37 | SSA def(nonSink0) | -| LocalDataFlow.cs:407:22:407:26 | "test " | LocalDataFlow.cs:407:20:407:37 | $"..." | -| LocalDataFlow.cs:407:28:407:35 | access to local variable nonSink0 | LocalDataFlow.cs:407:20:407:37 | $"..." | -| LocalDataFlow.cs:408:15:408:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:415:31:415:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:408:15:408:22 | access to local variable nonSink0 | LocalDataFlow.cs:415:31:415:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:411:13:411:34 | SSA def(sink70) | LocalDataFlow.cs:412:15:412:20 | access to local variable sink70 | -| LocalDataFlow.cs:411:22:411:34 | ... = ... | LocalDataFlow.cs:411:13:411:34 | SSA def(sink70) | -| LocalDataFlow.cs:411:22:411:34 | SSA def(sink0) | LocalDataFlow.cs:443:34:443:38 | access to local variable sink0 | -| LocalDataFlow.cs:411:22:411:34 | SSA def(sink0) | LocalDataFlow.cs:444:22:444:26 | access to local variable sink0 | -| LocalDataFlow.cs:411:30:411:34 | access to local variable sink0 | LocalDataFlow.cs:411:22:411:34 | ... = ... | -| LocalDataFlow.cs:411:30:411:34 | access to local variable sink0 | LocalDataFlow.cs:411:22:411:34 | SSA def(sink0) | -| LocalDataFlow.cs:412:15:412:20 | [post] access to local variable sink70 | LocalDataFlow.cs:419:13:419:18 | access to local variable sink70 | -| LocalDataFlow.cs:412:15:412:20 | access to local variable sink70 | LocalDataFlow.cs:419:13:419:18 | access to local variable sink70 | -| LocalDataFlow.cs:415:9:415:38 | SSA def(nonSink0) | LocalDataFlow.cs:416:15:416:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:415:20:415:38 | ... = ... | LocalDataFlow.cs:415:9:415:38 | SSA def(nonSink0) | -| LocalDataFlow.cs:415:31:415:38 | access to local variable nonSink0 | LocalDataFlow.cs:415:20:415:38 | ... = ... | -| LocalDataFlow.cs:416:15:416:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:423:13:423:20 | access to local variable nonSink0 | -| LocalDataFlow.cs:416:15:416:22 | access to local variable nonSink0 | LocalDataFlow.cs:423:13:423:20 | access to local variable nonSink0 | -| LocalDataFlow.cs:419:13:419:18 | access to local variable sink70 | LocalDataFlow.cs:419:23:419:35 | SSA def(sink71) | -| LocalDataFlow.cs:419:13:419:18 | access to local variable sink70 | LocalDataFlow.cs:427:17:427:22 | access to local variable sink70 | -| LocalDataFlow.cs:419:23:419:35 | SSA def(sink71) | LocalDataFlow.cs:420:19:420:24 | access to local variable sink71 | -| LocalDataFlow.cs:423:13:423:20 | access to local variable nonSink0 | LocalDataFlow.cs:423:25:423:40 | SSA def(nonSink16) | -| LocalDataFlow.cs:423:13:423:20 | access to local variable nonSink0 | LocalDataFlow.cs:435:17:435:24 | access to local variable nonSink0 | -| LocalDataFlow.cs:423:25:423:40 | SSA def(nonSink16) | LocalDataFlow.cs:424:19:424:27 | access to local variable nonSink16 | -| LocalDataFlow.cs:427:17:427:22 | access to local variable sink70 | LocalDataFlow.cs:429:18:429:30 | SSA def(sink72) | -| LocalDataFlow.cs:429:18:429:30 | SSA def(sink72) | LocalDataFlow.cs:430:23:430:28 | access to local variable sink72 | -| LocalDataFlow.cs:435:17:435:24 | access to local variable nonSink0 | LocalDataFlow.cs:437:18:437:33 | SSA def(nonSink17) | -| LocalDataFlow.cs:435:17:435:24 | access to local variable nonSink0 | LocalDataFlow.cs:443:22:443:29 | access to local variable nonSink0 | -| LocalDataFlow.cs:437:18:437:33 | SSA def(nonSink17) | LocalDataFlow.cs:438:23:438:31 | access to local variable nonSink17 | -| LocalDataFlow.cs:443:13:443:38 | SSA def(sink73) | LocalDataFlow.cs:445:15:445:20 | access to local variable sink73 | -| LocalDataFlow.cs:443:22:443:29 | access to local variable nonSink0 | LocalDataFlow.cs:443:22:443:38 | ... ?? ... | -| LocalDataFlow.cs:443:22:443:29 | access to local variable nonSink0 | LocalDataFlow.cs:444:31:444:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:443:22:443:38 | ... ?? ... | LocalDataFlow.cs:443:13:443:38 | SSA def(sink73) | -| LocalDataFlow.cs:443:34:443:38 | access to local variable sink0 | LocalDataFlow.cs:443:22:443:38 | ... ?? ... | -| LocalDataFlow.cs:443:34:443:38 | access to local variable sink0 | LocalDataFlow.cs:444:22:444:26 | access to local variable sink0 | -| LocalDataFlow.cs:444:13:444:38 | SSA def(sink74) | LocalDataFlow.cs:446:15:446:20 | access to local variable sink74 | -| LocalDataFlow.cs:444:22:444:26 | access to local variable sink0 | LocalDataFlow.cs:444:22:444:38 | ... ?? ... | -| LocalDataFlow.cs:444:22:444:38 | ... ?? ... | LocalDataFlow.cs:444:13:444:38 | SSA def(sink74) | -| LocalDataFlow.cs:444:31:444:38 | access to local variable nonSink0 | LocalDataFlow.cs:444:22:444:38 | ... ?? ... | -| LocalDataFlow.cs:464:28:464:30 | this | LocalDataFlow.cs:464:41:464:45 | this access | -| LocalDataFlow.cs:464:50:464:52 | this | LocalDataFlow.cs:464:56:464:60 | this access | -| LocalDataFlow.cs:464:50:464:52 | value | LocalDataFlow.cs:464:50:464:52 | value | -| LocalDataFlow.cs:464:50:464:52 | value | LocalDataFlow.cs:464:64:464:68 | access to parameter value | -| LocalDataFlow.cs:470:41:470:47 | tainted | LocalDataFlow.cs:470:41:470:47 | tainted | -| LocalDataFlow.cs:470:41:470:47 | tainted | LocalDataFlow.cs:472:15:472:21 | access to parameter tainted | -| LocalDataFlow.cs:475:44:475:53 | nonTainted | LocalDataFlow.cs:475:44:475:53 | nonTainted | -| LocalDataFlow.cs:475:44:475:53 | nonTainted | LocalDataFlow.cs:477:15:477:24 | access to parameter nonTainted | -| LocalDataFlow.cs:480:44:480:44 | x | LocalDataFlow.cs:480:44:480:44 | x | -| LocalDataFlow.cs:480:44:480:44 | x | LocalDataFlow.cs:483:21:483:21 | access to parameter x | -| LocalDataFlow.cs:480:67:480:68 | os | LocalDataFlow.cs:480:67:480:68 | os | -| LocalDataFlow.cs:480:67:480:68 | os | LocalDataFlow.cs:486:32:486:33 | access to parameter os | -| LocalDataFlow.cs:483:21:483:21 | access to parameter x | LocalDataFlow.cs:483:16:483:21 | ... = ... | -| LocalDataFlow.cs:486:32:486:33 | access to parameter os | LocalDataFlow.cs:486:26:486:33 | ... = ... | -| LocalDataFlow.cs:491:41:491:44 | args | LocalDataFlow.cs:491:41:491:44 | args | -| LocalDataFlow.cs:491:41:491:44 | args | LocalDataFlow.cs:493:29:493:32 | access to parameter args | -| LocalDataFlow.cs:493:29:493:32 | [post] access to parameter args | LocalDataFlow.cs:494:27:494:30 | access to parameter args | -| LocalDataFlow.cs:493:29:493:32 | access to parameter args | LocalDataFlow.cs:493:29:493:32 | call to operator implicit conversion | -| LocalDataFlow.cs:493:29:493:32 | access to parameter args | LocalDataFlow.cs:494:27:494:30 | access to parameter args | +| LocalDataFlow.cs:66:15:66:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:73:20:73:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:66:15:66:22 | access to local variable nonSink0 | LocalDataFlow.cs:73:20:73:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:69:13:69:32 | SSA def(sink5) | LocalDataFlow.cs:70:15:70:19 | access to local variable sink5 | +| LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | LocalDataFlow.cs:69:21:69:32 | ... + ... | +| LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | LocalDataFlow.cs:169:33:169:37 | access to local variable sink1 | +| LocalDataFlow.cs:69:21:69:32 | ... + ... | LocalDataFlow.cs:69:13:69:32 | SSA def(sink5) | +| LocalDataFlow.cs:69:29:69:32 | "ok" | LocalDataFlow.cs:69:21:69:32 | ... + ... | +| LocalDataFlow.cs:70:15:70:19 | [post] access to local variable sink5 | LocalDataFlow.cs:77:22:77:26 | access to local variable sink5 | +| LocalDataFlow.cs:70:15:70:19 | access to local variable sink5 | LocalDataFlow.cs:77:22:77:26 | access to local variable sink5 | +| LocalDataFlow.cs:73:9:73:36 | SSA def(nonSink0) | LocalDataFlow.cs:74:15:74:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:73:20:73:27 | access to local variable nonSink0 | LocalDataFlow.cs:73:20:73:36 | ... + ... | +| LocalDataFlow.cs:73:20:73:36 | ... + ... | LocalDataFlow.cs:73:9:73:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:73:31:73:36 | "test" | LocalDataFlow.cs:73:20:73:36 | ... + ... | +| LocalDataFlow.cs:74:15:74:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:81:21:81:28 | access to local variable nonSink0 | +| LocalDataFlow.cs:74:15:74:22 | access to local variable nonSink0 | LocalDataFlow.cs:81:21:81:28 | access to local variable nonSink0 | +| LocalDataFlow.cs:77:13:77:27 | SSA def(sink6) | LocalDataFlow.cs:78:15:78:19 | access to local variable sink6 | +| LocalDataFlow.cs:77:22:77:26 | access to local variable sink5 | LocalDataFlow.cs:77:13:77:27 | SSA def(sink6) | +| LocalDataFlow.cs:78:15:78:19 | [post] access to local variable sink6 | LocalDataFlow.cs:85:31:85:35 | [b (line 49): false] access to local variable sink6 | +| LocalDataFlow.cs:78:15:78:19 | access to local variable sink6 | LocalDataFlow.cs:85:31:85:35 | [b (line 49): false] access to local variable sink6 | +| LocalDataFlow.cs:81:9:81:29 | SSA def(nonSink0) | LocalDataFlow.cs:82:15:82:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:81:21:81:28 | access to local variable nonSink0 | LocalDataFlow.cs:81:9:81:29 | SSA def(nonSink0) | +| LocalDataFlow.cs:85:13:85:35 | [b (line 49): false] SSA def(sink7) | LocalDataFlow.cs:86:15:86:19 | [b (line 49): false] access to local variable sink7 | +| LocalDataFlow.cs:85:13:85:35 | [b (line 49): true] SSA def(sink7) | LocalDataFlow.cs:86:15:86:19 | [b (line 49): true] access to local variable sink7 | +| LocalDataFlow.cs:85:21:85:21 | access to parameter b | LocalDataFlow.cs:89:20:89:20 | [b (line 49): false] access to parameter b | +| LocalDataFlow.cs:85:21:85:21 | access to parameter b | LocalDataFlow.cs:89:20:89:20 | [b (line 49): true] access to parameter b | +| LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | LocalDataFlow.cs:85:13:85:35 | [b (line 49): false] SSA def(sink7) | +| LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | LocalDataFlow.cs:85:13:85:35 | [b (line 49): true] SSA def(sink7) | +| LocalDataFlow.cs:85:25:85:27 | [b (line 49): true] "a" | LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | +| LocalDataFlow.cs:85:31:85:35 | [b (line 49): false] access to local variable sink6 | LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | +| LocalDataFlow.cs:86:15:86:19 | [b (line 49): false] access to local variable sink7 | LocalDataFlow.cs:89:9:89:36 | SSA phi(sink7) | +| LocalDataFlow.cs:86:15:86:19 | [b (line 49): true] access to local variable sink7 | LocalDataFlow.cs:89:9:89:36 | SSA phi(sink7) | +| LocalDataFlow.cs:89:9:89:36 | SSA def(nonSink0) | LocalDataFlow.cs:90:15:90:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:89:9:89:36 | SSA phi(sink7) | LocalDataFlow.cs:93:29:93:33 | access to local variable sink7 | +| LocalDataFlow.cs:89:20:89:36 | [b (line 49): false] ... ? ... : ... | LocalDataFlow.cs:89:9:89:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:89:20:89:36 | [b (line 49): true] ... ? ... : ... | LocalDataFlow.cs:89:9:89:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:89:24:89:28 | "abc" | LocalDataFlow.cs:89:20:89:36 | [b (line 49): true] ... ? ... : ... | +| LocalDataFlow.cs:89:32:89:36 | "def" | LocalDataFlow.cs:89:20:89:36 | [b (line 49): false] ... ? ... : ... | +| LocalDataFlow.cs:90:15:90:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:90:15:90:22 | access to local variable nonSink0 | LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:93:13:93:33 | SSA def(sink8) | LocalDataFlow.cs:94:15:94:19 | access to local variable sink8 | +| LocalDataFlow.cs:93:21:93:33 | (...) ... | LocalDataFlow.cs:93:13:93:33 | SSA def(sink8) | +| LocalDataFlow.cs:93:29:93:33 | access to local variable sink7 | LocalDataFlow.cs:93:21:93:33 | (...) ... | +| LocalDataFlow.cs:94:15:94:19 | [post] access to local variable sink8 | LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | +| LocalDataFlow.cs:94:15:94:19 | access to local variable sink8 | LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | +| LocalDataFlow.cs:97:13:97:39 | SSA def(nonSink3) | LocalDataFlow.cs:98:15:98:22 | access to local variable nonSink3 | +| LocalDataFlow.cs:97:24:97:39 | (...) ... | LocalDataFlow.cs:97:13:97:39 | SSA def(nonSink3) | +| LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | LocalDataFlow.cs:97:24:97:39 | (...) ... | +| LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | LocalDataFlow.cs:105:20:105:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:101:13:101:35 | SSA def(sink9) | LocalDataFlow.cs:102:15:102:19 | access to local variable sink9 | +| LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | LocalDataFlow.cs:101:21:101:35 | ... as ... | +| LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | LocalDataFlow.cs:165:22:165:26 | access to local variable sink8 | +| LocalDataFlow.cs:101:21:101:35 | ... as ... | LocalDataFlow.cs:101:13:101:35 | SSA def(sink9) | +| LocalDataFlow.cs:102:15:102:19 | [post] access to local variable sink9 | LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | +| LocalDataFlow.cs:102:15:102:19 | access to local variable sink9 | LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | +| LocalDataFlow.cs:105:9:105:37 | SSA def(nonSink3) | LocalDataFlow.cs:106:15:106:22 | access to local variable nonSink3 | +| LocalDataFlow.cs:105:20:105:27 | access to local variable nonSink0 | LocalDataFlow.cs:105:20:105:37 | ... as ... | +| LocalDataFlow.cs:105:20:105:27 | access to local variable nonSink0 | LocalDataFlow.cs:114:22:114:29 | access to local variable nonSink0 | +| LocalDataFlow.cs:105:20:105:37 | ... as ... | LocalDataFlow.cs:105:9:105:37 | SSA def(nonSink3) | +| LocalDataFlow.cs:106:15:106:22 | [post] access to local variable nonSink3 | LocalDataFlow.cs:171:33:171:40 | access to local variable nonSink3 | +| LocalDataFlow.cs:106:15:106:22 | access to local variable nonSink3 | LocalDataFlow.cs:171:33:171:40 | access to local variable nonSink3 | +| LocalDataFlow.cs:109:13:109:39 | SSA def(sink15) | LocalDataFlow.cs:110:15:110:20 | access to local variable sink15 | +| LocalDataFlow.cs:109:22:109:39 | call to method Parse | LocalDataFlow.cs:109:13:109:39 | SSA def(sink15) | +| LocalDataFlow.cs:109:34:109:38 | [post] access to local variable sink9 | LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | +| LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | LocalDataFlow.cs:109:22:109:39 | call to method Parse | +| LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | +| LocalDataFlow.cs:110:15:110:20 | access to local variable sink15 | LocalDataFlow.cs:161:22:161:27 | access to local variable sink15 | +| LocalDataFlow.cs:112:13:112:56 | SSA def(sink16) | LocalDataFlow.cs:113:15:113:20 | access to local variable sink16 | +| LocalDataFlow.cs:112:22:112:56 | call to method TryParse | LocalDataFlow.cs:112:13:112:56 | SSA def(sink16) | +| LocalDataFlow.cs:112:37:112:41 | [post] access to local variable sink9 | LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | +| LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | LocalDataFlow.cs:112:22:112:56 | call to method TryParse | +| LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | +| LocalDataFlow.cs:114:13:114:49 | SSA def(sink17) | LocalDataFlow.cs:115:15:115:20 | access to local variable sink17 | +| LocalDataFlow.cs:114:22:114:29 | [post] access to local variable nonSink0 | LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | +| LocalDataFlow.cs:114:22:114:29 | access to local variable nonSink0 | LocalDataFlow.cs:114:22:114:49 | call to method Replace | +| LocalDataFlow.cs:114:22:114:29 | access to local variable nonSink0 | LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | +| LocalDataFlow.cs:114:22:114:49 | call to method Replace | LocalDataFlow.cs:114:13:114:49 | SSA def(sink17) | +| LocalDataFlow.cs:114:44:114:48 | [post] access to local variable sink9 | LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | +| LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | LocalDataFlow.cs:114:22:114:49 | call to method Replace | +| LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | +| LocalDataFlow.cs:116:13:116:51 | SSA def(sink18) | LocalDataFlow.cs:117:15:117:20 | access to local variable sink18 | +| LocalDataFlow.cs:116:22:116:51 | call to method Format | LocalDataFlow.cs:116:13:116:51 | SSA def(sink18) | +| LocalDataFlow.cs:116:36:116:43 | [post] access to local variable nonSink0 | LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | LocalDataFlow.cs:116:22:116:51 | call to method Format | +| LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:116:46:116:50 | [post] access to local variable sink9 | LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | +| LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | LocalDataFlow.cs:116:22:116:51 | call to method Format | +| LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | +| LocalDataFlow.cs:117:15:117:20 | [post] access to local variable sink18 | LocalDataFlow.cs:118:36:118:41 | access to local variable sink18 | +| LocalDataFlow.cs:117:15:117:20 | access to local variable sink18 | LocalDataFlow.cs:118:36:118:41 | access to local variable sink18 | +| LocalDataFlow.cs:118:13:118:52 | SSA def(sink19) | LocalDataFlow.cs:119:15:119:20 | access to local variable sink19 | +| LocalDataFlow.cs:118:22:118:52 | call to method Format | LocalDataFlow.cs:118:13:118:52 | SSA def(sink19) | +| LocalDataFlow.cs:118:36:118:41 | access to local variable sink18 | LocalDataFlow.cs:118:22:118:52 | call to method Format | +| LocalDataFlow.cs:118:44:118:51 | [post] access to local variable nonSink0 | LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | LocalDataFlow.cs:118:22:118:52 | call to method Format | +| LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:120:13:120:38 | SSA def(sink45) | LocalDataFlow.cs:121:15:121:20 | access to local variable sink45 | +| LocalDataFlow.cs:120:22:120:38 | call to method Parse | LocalDataFlow.cs:120:13:120:38 | SSA def(sink45) | +| LocalDataFlow.cs:120:33:120:37 | [post] access to local variable sink9 | LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | +| LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | LocalDataFlow.cs:120:22:120:38 | call to method Parse | +| LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | +| LocalDataFlow.cs:123:13:123:56 | SSA def(sink46) | LocalDataFlow.cs:124:15:124:20 | access to local variable sink46 | +| LocalDataFlow.cs:123:22:123:56 | call to method TryParse | LocalDataFlow.cs:123:13:123:56 | SSA def(sink46) | +| LocalDataFlow.cs:123:36:123:40 | [post] access to local variable sink9 | LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | +| LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | LocalDataFlow.cs:123:22:123:56 | call to method TryParse | +| LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | +| LocalDataFlow.cs:124:15:124:20 | access to local variable sink46 | LocalDataFlow.cs:125:37:125:42 | access to local variable sink46 | +| LocalDataFlow.cs:125:13:125:43 | SSA def(sink47) | LocalDataFlow.cs:126:15:126:20 | access to local variable sink47 | +| LocalDataFlow.cs:125:22:125:43 | call to method ToByte | LocalDataFlow.cs:125:13:125:43 | SSA def(sink47) | +| LocalDataFlow.cs:125:37:125:42 | access to local variable sink46 | LocalDataFlow.cs:125:22:125:43 | call to method ToByte | +| LocalDataFlow.cs:126:15:126:20 | access to local variable sink47 | LocalDataFlow.cs:127:40:127:45 | access to local variable sink47 | +| LocalDataFlow.cs:127:13:127:46 | SSA def(sink49) | LocalDataFlow.cs:128:15:128:20 | access to local variable sink49 | +| LocalDataFlow.cs:127:22:127:46 | call to method Concat | LocalDataFlow.cs:127:13:127:46 | SSA def(sink49) | +| LocalDataFlow.cs:127:36:127:37 | "" | LocalDataFlow.cs:127:22:127:46 | call to method Concat | +| LocalDataFlow.cs:127:40:127:45 | (...) ... | LocalDataFlow.cs:127:22:127:46 | call to method Concat | +| LocalDataFlow.cs:127:40:127:45 | access to local variable sink47 | LocalDataFlow.cs:127:40:127:45 | (...) ... | +| LocalDataFlow.cs:128:15:128:20 | [post] access to local variable sink49 | LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | +| LocalDataFlow.cs:128:15:128:20 | access to local variable sink49 | LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | +| LocalDataFlow.cs:129:13:129:40 | SSA def(sink50) | LocalDataFlow.cs:130:15:130:20 | access to local variable sink50 | +| LocalDataFlow.cs:129:22:129:40 | call to method Copy | LocalDataFlow.cs:129:13:129:40 | SSA def(sink50) | +| LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | LocalDataFlow.cs:129:22:129:40 | call to method Copy | +| LocalDataFlow.cs:130:15:130:20 | [post] access to local variable sink50 | LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | +| LocalDataFlow.cs:130:15:130:20 | access to local variable sink50 | LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | +| LocalDataFlow.cs:131:13:131:54 | SSA def(sink51) | LocalDataFlow.cs:132:15:132:20 | access to local variable sink51 | +| LocalDataFlow.cs:131:22:131:54 | call to method Join | LocalDataFlow.cs:131:13:131:54 | SSA def(sink51) | +| LocalDataFlow.cs:131:34:131:37 | ", " | LocalDataFlow.cs:131:22:131:54 | call to method Join | +| LocalDataFlow.cs:131:40:131:41 | "" | LocalDataFlow.cs:131:22:131:54 | call to method Join | +| LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | LocalDataFlow.cs:131:22:131:54 | call to method Join | +| LocalDataFlow.cs:131:52:131:53 | "" | LocalDataFlow.cs:131:22:131:54 | call to method Join | +| LocalDataFlow.cs:132:15:132:20 | [post] access to local variable sink51 | LocalDataFlow.cs:133:35:133:40 | access to local variable sink51 | +| LocalDataFlow.cs:132:15:132:20 | access to local variable sink51 | LocalDataFlow.cs:133:35:133:40 | access to local variable sink51 | +| LocalDataFlow.cs:133:13:133:41 | SSA def(sink52) | LocalDataFlow.cs:134:15:134:20 | access to local variable sink52 | +| LocalDataFlow.cs:133:22:133:23 | "" | LocalDataFlow.cs:133:22:133:41 | call to method Insert | +| LocalDataFlow.cs:133:22:133:41 | call to method Insert | LocalDataFlow.cs:133:13:133:41 | SSA def(sink52) | +| LocalDataFlow.cs:133:35:133:40 | access to local variable sink51 | LocalDataFlow.cs:133:22:133:41 | call to method Insert | +| LocalDataFlow.cs:137:9:137:40 | SSA def(nonSink2) | LocalDataFlow.cs:138:15:138:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:137:20:137:40 | call to method Parse | LocalDataFlow.cs:137:9:137:40 | SSA def(nonSink2) | +| LocalDataFlow.cs:137:32:137:39 | [post] access to local variable nonSink0 | LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | LocalDataFlow.cs:137:20:137:40 | call to method Parse | +| LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:139:13:139:61 | SSA def(nonSink7) | LocalDataFlow.cs:140:15:140:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:139:24:139:61 | call to method TryParse | LocalDataFlow.cs:139:13:139:61 | SSA def(nonSink7) | +| LocalDataFlow.cs:139:39:139:46 | [post] access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | LocalDataFlow.cs:139:24:139:61 | call to method TryParse | +| LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:141:9:141:50 | SSA def(nonSink0) | LocalDataFlow.cs:142:15:142:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:141:20:141:27 | [post] access to local variable nonSink0 | LocalDataFlow.cs:141:42:141:49 | access to local variable nonSink0 | +| LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:50 | call to method Replace | +| LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | LocalDataFlow.cs:141:42:141:49 | access to local variable nonSink0 | +| LocalDataFlow.cs:141:20:141:50 | call to method Replace | LocalDataFlow.cs:141:9:141:50 | SSA def(nonSink0) | +| LocalDataFlow.cs:141:42:141:49 | access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:50 | call to method Replace | +| LocalDataFlow.cs:142:15:142:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:142:15:142:22 | access to local variable nonSink0 | LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:143:9:143:52 | SSA def(nonSink0) | LocalDataFlow.cs:144:15:144:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:143:20:143:52 | call to method Format | LocalDataFlow.cs:143:9:143:52 | SSA def(nonSink0) | +| LocalDataFlow.cs:143:34:143:41 | [post] access to local variable nonSink0 | LocalDataFlow.cs:143:44:143:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | LocalDataFlow.cs:143:20:143:52 | call to method Format | +| LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | LocalDataFlow.cs:143:44:143:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:143:44:143:51 | access to local variable nonSink0 | LocalDataFlow.cs:143:20:143:52 | call to method Format | +| LocalDataFlow.cs:144:15:144:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:144:15:144:22 | access to local variable nonSink0 | LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:145:9:145:39 | SSA def(nonSink7) | LocalDataFlow.cs:146:15:146:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:145:20:145:39 | call to method Parse | LocalDataFlow.cs:145:9:145:39 | SSA def(nonSink7) | +| LocalDataFlow.cs:145:31:145:38 | [post] access to local variable nonSink0 | LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | LocalDataFlow.cs:145:20:145:39 | call to method Parse | +| LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:147:9:147:57 | SSA def(nonSink7) | LocalDataFlow.cs:148:15:148:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:147:20:147:57 | call to method TryParse | LocalDataFlow.cs:147:9:147:57 | SSA def(nonSink7) | +| LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | LocalDataFlow.cs:147:20:147:57 | call to method TryParse | +| LocalDataFlow.cs:148:15:148:22 | access to local variable nonSink7 | LocalDataFlow.cs:149:40:149:47 | access to local variable nonSink7 | +| LocalDataFlow.cs:149:13:149:48 | SSA def(nonSink14) | LocalDataFlow.cs:150:15:150:23 | access to local variable nonSink14 | +| LocalDataFlow.cs:149:25:149:48 | call to method ToByte | LocalDataFlow.cs:149:13:149:48 | SSA def(nonSink14) | +| LocalDataFlow.cs:149:40:149:47 | access to local variable nonSink7 | LocalDataFlow.cs:149:25:149:48 | call to method ToByte | +| LocalDataFlow.cs:149:40:149:47 | access to local variable nonSink7 | LocalDataFlow.cs:151:38:151:45 | access to local variable nonSink7 | +| LocalDataFlow.cs:151:9:151:46 | SSA def(nonSink0) | LocalDataFlow.cs:152:15:152:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:151:20:151:46 | call to method Concat | LocalDataFlow.cs:151:9:151:46 | SSA def(nonSink0) | +| LocalDataFlow.cs:151:34:151:35 | "" | LocalDataFlow.cs:151:20:151:46 | call to method Concat | +| LocalDataFlow.cs:151:38:151:45 | (...) ... | LocalDataFlow.cs:151:20:151:46 | call to method Concat | +| LocalDataFlow.cs:151:38:151:45 | access to local variable nonSink7 | LocalDataFlow.cs:151:38:151:45 | (...) ... | +| LocalDataFlow.cs:152:15:152:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:152:15:152:22 | access to local variable nonSink0 | LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:153:9:153:40 | SSA def(nonSink0) | LocalDataFlow.cs:154:15:154:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:153:20:153:40 | call to method Copy | LocalDataFlow.cs:153:9:153:40 | SSA def(nonSink0) | +| LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | LocalDataFlow.cs:153:20:153:40 | call to method Copy | +| LocalDataFlow.cs:154:15:154:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | +| LocalDataFlow.cs:154:15:154:22 | access to local variable nonSink0 | LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | +| LocalDataFlow.cs:155:9:155:54 | SSA def(nonSink0) | LocalDataFlow.cs:156:15:156:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:155:20:155:54 | call to method Join | LocalDataFlow.cs:155:9:155:54 | SSA def(nonSink0) | +| LocalDataFlow.cs:155:32:155:35 | ", " | LocalDataFlow.cs:155:20:155:54 | call to method Join | +| LocalDataFlow.cs:155:38:155:39 | "" | LocalDataFlow.cs:155:20:155:54 | call to method Join | +| LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | LocalDataFlow.cs:155:20:155:54 | call to method Join | +| LocalDataFlow.cs:155:52:155:53 | "" | LocalDataFlow.cs:155:20:155:54 | call to method Join | +| LocalDataFlow.cs:156:15:156:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:157:33:157:40 | access to local variable nonSink0 | +| LocalDataFlow.cs:156:15:156:22 | access to local variable nonSink0 | LocalDataFlow.cs:157:33:157:40 | access to local variable nonSink0 | +| LocalDataFlow.cs:157:9:157:41 | SSA def(nonSink0) | LocalDataFlow.cs:158:15:158:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:157:20:157:21 | "" | LocalDataFlow.cs:157:20:157:41 | call to method Insert | +| LocalDataFlow.cs:157:20:157:41 | call to method Insert | LocalDataFlow.cs:157:9:157:41 | SSA def(nonSink0) | +| LocalDataFlow.cs:157:33:157:40 | access to local variable nonSink0 | LocalDataFlow.cs:157:20:157:41 | call to method Insert | +| LocalDataFlow.cs:158:15:158:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:195:39:195:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:158:15:158:22 | access to local variable nonSink0 | LocalDataFlow.cs:195:39:195:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:161:13:161:32 | SSA def(sink20) | LocalDataFlow.cs:162:15:162:20 | access to local variable sink20 | +| LocalDataFlow.cs:161:22:161:27 | access to local variable sink15 | LocalDataFlow.cs:161:22:161:32 | ... > ... | +| LocalDataFlow.cs:161:22:161:32 | ... > ... | LocalDataFlow.cs:161:13:161:32 | SSA def(sink20) | +| LocalDataFlow.cs:162:15:162:20 | access to local variable sink20 | LocalDataFlow.cs:175:22:175:27 | access to local variable sink20 | +| LocalDataFlow.cs:163:13:163:40 | SSA def(sink21) | LocalDataFlow.cs:164:15:164:20 | access to local variable sink21 | +| LocalDataFlow.cs:163:22:163:26 | [post] access to local variable sink9 | LocalDataFlow.cs:183:37:183:41 | access to local variable sink9 | +| LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | LocalDataFlow.cs:163:22:163:40 | call to method Equals | +| LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | LocalDataFlow.cs:183:37:183:41 | access to local variable sink9 | +| LocalDataFlow.cs:163:22:163:40 | call to method Equals | LocalDataFlow.cs:163:13:163:40 | SSA def(sink21) | +| LocalDataFlow.cs:165:13:165:45 | SSA def(sink22) | LocalDataFlow.cs:166:15:166:20 | access to local variable sink22 | +| LocalDataFlow.cs:165:22:165:26 | [post] access to local variable sink8 | LocalDataFlow.cs:171:20:171:24 | access to local variable sink8 | +| LocalDataFlow.cs:165:22:165:26 | access to local variable sink8 | LocalDataFlow.cs:165:22:165:45 | call to method Equals | +| LocalDataFlow.cs:165:22:165:26 | access to local variable sink8 | LocalDataFlow.cs:171:20:171:24 | access to local variable sink8 | +| LocalDataFlow.cs:165:22:165:45 | call to method Equals | LocalDataFlow.cs:165:13:165:45 | SSA def(sink22) | +| LocalDataFlow.cs:165:43:165:44 | 41 | LocalDataFlow.cs:165:35:165:44 | (...) ... | +| LocalDataFlow.cs:169:9:169:38 | SSA def(nonSink7) | LocalDataFlow.cs:170:15:170:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:169:20:169:24 | [post] access to local variable sink0 | LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | +| LocalDataFlow.cs:169:20:169:24 | access to local variable sink0 | LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | +| LocalDataFlow.cs:169:20:169:38 | call to method Equals | LocalDataFlow.cs:169:9:169:38 | SSA def(nonSink7) | +| LocalDataFlow.cs:169:33:169:37 | [post] access to local variable sink1 | LocalDataFlow.cs:286:30:286:34 | access to local variable sink1 | +| LocalDataFlow.cs:169:33:169:37 | access to local variable sink1 | LocalDataFlow.cs:286:30:286:34 | access to local variable sink1 | +| LocalDataFlow.cs:171:9:171:41 | SSA def(nonSink7) | LocalDataFlow.cs:172:15:172:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:171:20:171:41 | call to method Equals | LocalDataFlow.cs:171:9:171:41 | SSA def(nonSink7) | +| LocalDataFlow.cs:172:15:172:22 | access to local variable nonSink7 | LocalDataFlow.cs:179:20:179:27 | access to local variable nonSink7 | +| LocalDataFlow.cs:175:13:175:36 | SSA def(sink25) | LocalDataFlow.cs:176:15:176:20 | access to local variable sink25 | +| LocalDataFlow.cs:175:22:175:27 | access to local variable sink20 | LocalDataFlow.cs:175:22:175:36 | ... \|\| ... | +| LocalDataFlow.cs:175:22:175:36 | ... \|\| ... | LocalDataFlow.cs:175:13:175:36 | SSA def(sink25) | +| LocalDataFlow.cs:175:32:175:36 | false | LocalDataFlow.cs:175:22:175:36 | ... \|\| ... | +| LocalDataFlow.cs:179:9:179:36 | SSA def(nonSink7) | LocalDataFlow.cs:180:15:180:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:179:20:179:27 | access to local variable nonSink7 | LocalDataFlow.cs:179:20:179:36 | ... \|\| ... | +| LocalDataFlow.cs:179:20:179:36 | ... \|\| ... | LocalDataFlow.cs:179:9:179:36 | SSA def(nonSink7) | +| LocalDataFlow.cs:179:32:179:36 | false | LocalDataFlow.cs:179:20:179:36 | ... \|\| ... | +| LocalDataFlow.cs:183:13:183:42 | SSA def(sink26) | LocalDataFlow.cs:184:15:184:20 | access to local variable sink26 | +| LocalDataFlow.cs:183:22:183:42 | object creation of type Uri | LocalDataFlow.cs:183:13:183:42 | SSA def(sink26) | +| LocalDataFlow.cs:183:37:183:41 | access to local variable sink9 | LocalDataFlow.cs:183:22:183:42 | object creation of type Uri | +| LocalDataFlow.cs:184:15:184:20 | [post] access to local variable sink26 | LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | +| LocalDataFlow.cs:184:15:184:20 | access to local variable sink26 | LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | +| LocalDataFlow.cs:185:13:185:38 | SSA def(sink27) | LocalDataFlow.cs:186:15:186:20 | access to local variable sink27 | +| LocalDataFlow.cs:185:22:185:27 | [post] access to local variable sink26 | LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | +| LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | LocalDataFlow.cs:185:22:185:38 | call to method ToString | +| LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | +| LocalDataFlow.cs:185:22:185:38 | call to method ToString | LocalDataFlow.cs:185:13:185:38 | SSA def(sink27) | +| LocalDataFlow.cs:187:13:187:40 | SSA def(sink28) | LocalDataFlow.cs:188:15:188:20 | access to local variable sink28 | +| LocalDataFlow.cs:187:22:187:27 | [post] access to local variable sink26 | LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | +| LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | LocalDataFlow.cs:187:22:187:40 | access to property PathAndQuery | +| LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | +| LocalDataFlow.cs:187:22:187:40 | access to property PathAndQuery | LocalDataFlow.cs:187:13:187:40 | SSA def(sink28) | +| LocalDataFlow.cs:189:13:189:33 | SSA def(sink29) | LocalDataFlow.cs:190:15:190:20 | access to local variable sink29 | +| LocalDataFlow.cs:189:22:189:27 | [post] access to local variable sink26 | LocalDataFlow.cs:191:22:191:27 | access to local variable sink26 | +| LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | LocalDataFlow.cs:189:22:189:33 | access to property Query | +| LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | LocalDataFlow.cs:191:22:191:27 | access to local variable sink26 | +| LocalDataFlow.cs:189:22:189:33 | access to property Query | LocalDataFlow.cs:189:13:189:33 | SSA def(sink29) | +| LocalDataFlow.cs:191:13:191:42 | SSA def(sink30) | LocalDataFlow.cs:192:15:192:20 | access to local variable sink30 | +| LocalDataFlow.cs:191:22:191:27 | access to local variable sink26 | LocalDataFlow.cs:191:22:191:42 | access to property OriginalString | +| LocalDataFlow.cs:191:22:191:42 | access to property OriginalString | LocalDataFlow.cs:191:13:191:42 | SSA def(sink30) | +| LocalDataFlow.cs:192:15:192:20 | [post] access to local variable sink30 | LocalDataFlow.cs:207:49:207:54 | access to local variable sink30 | +| LocalDataFlow.cs:192:15:192:20 | access to local variable sink30 | LocalDataFlow.cs:207:49:207:54 | access to local variable sink30 | +| LocalDataFlow.cs:195:13:195:47 | SSA def(nonSink8) | LocalDataFlow.cs:196:15:196:22 | access to local variable nonSink8 | +| LocalDataFlow.cs:195:24:195:47 | object creation of type Uri | LocalDataFlow.cs:195:13:195:47 | SSA def(nonSink8) | +| LocalDataFlow.cs:195:39:195:46 | access to local variable nonSink0 | LocalDataFlow.cs:195:24:195:47 | object creation of type Uri | +| LocalDataFlow.cs:196:15:196:22 | [post] access to local variable nonSink8 | LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:196:15:196:22 | access to local variable nonSink8 | LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:197:9:197:38 | SSA def(nonSink0) | LocalDataFlow.cs:198:15:198:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:197:20:197:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | LocalDataFlow.cs:197:20:197:38 | call to method ToString | +| LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:197:20:197:38 | call to method ToString | LocalDataFlow.cs:197:9:197:38 | SSA def(nonSink0) | +| LocalDataFlow.cs:199:9:199:40 | SSA def(nonSink0) | LocalDataFlow.cs:200:15:200:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:199:20:199:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | LocalDataFlow.cs:199:20:199:40 | access to property PathAndQuery | +| LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:199:20:199:40 | access to property PathAndQuery | LocalDataFlow.cs:199:9:199:40 | SSA def(nonSink0) | +| LocalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) | LocalDataFlow.cs:202:15:202:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:201:20:201:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:203:20:203:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | LocalDataFlow.cs:201:20:201:33 | access to property Query | +| LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | LocalDataFlow.cs:203:20:203:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:201:20:201:33 | access to property Query | LocalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) | +| LocalDataFlow.cs:203:9:203:42 | SSA def(nonSink0) | LocalDataFlow.cs:204:15:204:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:203:20:203:27 | access to local variable nonSink8 | LocalDataFlow.cs:203:20:203:42 | access to property OriginalString | +| LocalDataFlow.cs:203:20:203:42 | access to property OriginalString | LocalDataFlow.cs:203:9:203:42 | SSA def(nonSink0) | +| LocalDataFlow.cs:204:15:204:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:213:51:213:58 | access to local variable nonSink0 | +| LocalDataFlow.cs:204:15:204:22 | access to local variable nonSink0 | LocalDataFlow.cs:213:51:213:58 | access to local variable nonSink0 | +| LocalDataFlow.cs:207:13:207:55 | SSA def(sink31) | LocalDataFlow.cs:208:15:208:20 | access to local variable sink31 | +| LocalDataFlow.cs:207:22:207:55 | object creation of type StringReader | LocalDataFlow.cs:207:13:207:55 | SSA def(sink31) | +| LocalDataFlow.cs:207:49:207:54 | access to local variable sink30 | LocalDataFlow.cs:207:22:207:55 | object creation of type StringReader | +| LocalDataFlow.cs:208:15:208:20 | [post] access to local variable sink31 | LocalDataFlow.cs:209:22:209:27 | access to local variable sink31 | +| LocalDataFlow.cs:208:15:208:20 | access to local variable sink31 | LocalDataFlow.cs:209:22:209:27 | access to local variable sink31 | +| LocalDataFlow.cs:209:13:209:39 | SSA def(sink32) | LocalDataFlow.cs:210:15:210:20 | access to local variable sink32 | +| LocalDataFlow.cs:209:22:209:27 | access to local variable sink31 | LocalDataFlow.cs:209:22:209:39 | call to method ReadToEnd | +| LocalDataFlow.cs:209:22:209:39 | call to method ReadToEnd | LocalDataFlow.cs:209:13:209:39 | SSA def(sink32) | +| LocalDataFlow.cs:210:15:210:20 | [post] access to local variable sink32 | LocalDataFlow.cs:219:30:219:35 | access to local variable sink32 | +| LocalDataFlow.cs:210:15:210:20 | access to local variable sink32 | LocalDataFlow.cs:219:30:219:35 | access to local variable sink32 | +| LocalDataFlow.cs:213:13:213:59 | SSA def(nonSink9) | LocalDataFlow.cs:214:15:214:22 | access to local variable nonSink9 | +| LocalDataFlow.cs:213:24:213:59 | object creation of type StringReader | LocalDataFlow.cs:213:13:213:59 | SSA def(nonSink9) | +| LocalDataFlow.cs:213:51:213:58 | access to local variable nonSink0 | LocalDataFlow.cs:213:24:213:59 | object creation of type StringReader | +| LocalDataFlow.cs:214:15:214:22 | [post] access to local variable nonSink9 | LocalDataFlow.cs:215:20:215:27 | access to local variable nonSink9 | +| LocalDataFlow.cs:214:15:214:22 | access to local variable nonSink9 | LocalDataFlow.cs:215:20:215:27 | access to local variable nonSink9 | +| LocalDataFlow.cs:215:9:215:39 | SSA def(nonSink0) | LocalDataFlow.cs:216:15:216:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:215:20:215:27 | access to local variable nonSink9 | LocalDataFlow.cs:215:20:215:39 | call to method ReadToEnd | +| LocalDataFlow.cs:215:20:215:39 | call to method ReadToEnd | LocalDataFlow.cs:215:9:215:39 | SSA def(nonSink0) | +| LocalDataFlow.cs:216:15:216:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:225:28:225:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:216:15:216:22 | access to local variable nonSink0 | LocalDataFlow.cs:225:28:225:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:219:13:219:127 | SSA def(sink33) | LocalDataFlow.cs:220:15:220:20 | access to local variable sink33 | +| LocalDataFlow.cs:219:22:219:127 | (...) ... | LocalDataFlow.cs:219:13:219:127 | SSA def(sink33) | +| LocalDataFlow.cs:219:30:219:35 | access to local variable sink32 | LocalDataFlow.cs:219:30:219:48 | call to method Substring | +| LocalDataFlow.cs:219:30:219:48 | call to method Substring | LocalDataFlow.cs:219:30:219:67 | call to method ToLowerInvariant | +| LocalDataFlow.cs:219:30:219:67 | call to method ToLowerInvariant | LocalDataFlow.cs:219:30:219:77 | call to method ToUpper | +| LocalDataFlow.cs:219:30:219:77 | call to method ToUpper | LocalDataFlow.cs:219:30:219:87 | call to method Trim | +| LocalDataFlow.cs:219:30:219:87 | call to method Trim | LocalDataFlow.cs:219:30:219:105 | call to method Replace | +| LocalDataFlow.cs:219:30:219:105 | call to method Replace | LocalDataFlow.cs:219:30:219:119 | call to method Insert | +| LocalDataFlow.cs:219:30:219:119 | call to method Insert | LocalDataFlow.cs:219:30:219:127 | call to method Clone | +| LocalDataFlow.cs:219:30:219:127 | call to method Clone | LocalDataFlow.cs:219:22:219:127 | (...) ... | +| LocalDataFlow.cs:219:102:219:104 | "b" | LocalDataFlow.cs:219:30:219:105 | call to method Replace | +| LocalDataFlow.cs:219:117:219:118 | "" | LocalDataFlow.cs:219:30:219:119 | call to method Insert | +| LocalDataFlow.cs:220:15:220:20 | [post] access to local variable sink33 | LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | +| LocalDataFlow.cs:220:15:220:20 | access to local variable sink33 | LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | +| LocalDataFlow.cs:221:13:221:63 | SSA def(sink48) | LocalDataFlow.cs:222:15:222:20 | access to local variable sink48 | +| LocalDataFlow.cs:221:22:221:27 | [post] access to local variable sink33 | LocalDataFlow.cs:231:40:231:45 | access to local variable sink33 | +| LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | LocalDataFlow.cs:221:22:221:39 | call to method Normalize | +| LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | LocalDataFlow.cs:231:40:231:45 | access to local variable sink33 | +| LocalDataFlow.cs:221:22:221:39 | call to method Normalize | LocalDataFlow.cs:221:22:221:52 | call to method Remove | +| LocalDataFlow.cs:221:22:221:52 | call to method Remove | LocalDataFlow.cs:221:22:221:63 | call to method Split | +| LocalDataFlow.cs:221:22:221:63 | call to method Split | LocalDataFlow.cs:221:13:221:63 | SSA def(sink48) | +| LocalDataFlow.cs:225:9:225:127 | SSA def(nonSink0) | LocalDataFlow.cs:226:15:226:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:225:20:225:127 | (...) ... | LocalDataFlow.cs:225:9:225:127 | SSA def(nonSink0) | +| LocalDataFlow.cs:225:28:225:35 | access to local variable nonSink0 | LocalDataFlow.cs:225:28:225:48 | call to method Substring | +| LocalDataFlow.cs:225:28:225:48 | call to method Substring | LocalDataFlow.cs:225:28:225:67 | call to method ToLowerInvariant | +| LocalDataFlow.cs:225:28:225:67 | call to method ToLowerInvariant | LocalDataFlow.cs:225:28:225:77 | call to method ToUpper | +| LocalDataFlow.cs:225:28:225:77 | call to method ToUpper | LocalDataFlow.cs:225:28:225:87 | call to method Trim | +| LocalDataFlow.cs:225:28:225:87 | call to method Trim | LocalDataFlow.cs:225:28:225:105 | call to method Replace | +| LocalDataFlow.cs:225:28:225:105 | call to method Replace | LocalDataFlow.cs:225:28:225:119 | call to method Insert | +| LocalDataFlow.cs:225:28:225:119 | call to method Insert | LocalDataFlow.cs:225:28:225:127 | call to method Clone | +| LocalDataFlow.cs:225:28:225:127 | call to method Clone | LocalDataFlow.cs:225:20:225:127 | (...) ... | +| LocalDataFlow.cs:225:102:225:104 | "b" | LocalDataFlow.cs:225:28:225:105 | call to method Replace | +| LocalDataFlow.cs:225:117:225:118 | "" | LocalDataFlow.cs:225:28:225:119 | call to method Insert | +| LocalDataFlow.cs:226:15:226:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | +| LocalDataFlow.cs:226:15:226:22 | access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | +| LocalDataFlow.cs:227:13:227:68 | SSA def(nonSink15) | LocalDataFlow.cs:228:15:228:23 | access to local variable nonSink15 | +| LocalDataFlow.cs:227:25:227:32 | [post] access to local variable nonSink0 | LocalDataFlow.cs:240:43:240:50 | access to local variable nonSink0 | +| LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:44 | call to method Normalize | +| LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | LocalDataFlow.cs:240:43:240:50 | access to local variable nonSink0 | +| LocalDataFlow.cs:227:25:227:44 | call to method Normalize | LocalDataFlow.cs:227:25:227:57 | call to method Remove | +| LocalDataFlow.cs:227:25:227:57 | call to method Remove | LocalDataFlow.cs:227:25:227:68 | call to method Split | +| LocalDataFlow.cs:227:25:227:68 | call to method Split | LocalDataFlow.cs:227:13:227:68 | SSA def(nonSink15) | +| LocalDataFlow.cs:231:13:231:46 | SSA def(sink34) | LocalDataFlow.cs:232:15:232:20 | access to local variable sink34 | +| LocalDataFlow.cs:231:22:231:46 | object creation of type StringBuilder | LocalDataFlow.cs:231:13:231:46 | SSA def(sink34) | +| LocalDataFlow.cs:231:40:231:45 | access to local variable sink33 | LocalDataFlow.cs:231:22:231:46 | object creation of type StringBuilder | +| LocalDataFlow.cs:232:15:232:20 | [post] access to local variable sink34 | LocalDataFlow.cs:233:22:233:27 | access to local variable sink34 | +| LocalDataFlow.cs:232:15:232:20 | access to local variable sink34 | LocalDataFlow.cs:233:22:233:27 | access to local variable sink34 | +| LocalDataFlow.cs:233:13:233:38 | SSA def(sink35) | LocalDataFlow.cs:234:15:234:20 | access to local variable sink35 | +| LocalDataFlow.cs:233:22:233:27 | access to local variable sink34 | LocalDataFlow.cs:233:22:233:38 | call to method ToString | +| LocalDataFlow.cs:233:22:233:38 | call to method ToString | LocalDataFlow.cs:233:13:233:38 | SSA def(sink35) | +| LocalDataFlow.cs:234:15:234:20 | [post] access to local variable sink35 | LocalDataFlow.cs:236:27:236:32 | access to local variable sink35 | +| LocalDataFlow.cs:234:15:234:20 | access to local variable sink35 | LocalDataFlow.cs:236:27:236:32 | access to local variable sink35 | +| LocalDataFlow.cs:235:13:235:42 | SSA def(sink36) | LocalDataFlow.cs:236:9:236:14 | access to local variable sink36 | +| LocalDataFlow.cs:235:22:235:42 | object creation of type StringBuilder | LocalDataFlow.cs:235:13:235:42 | SSA def(sink36) | +| LocalDataFlow.cs:235:40:235:41 | "" | LocalDataFlow.cs:235:22:235:42 | object creation of type StringBuilder | +| LocalDataFlow.cs:236:9:236:14 | [post] access to local variable sink36 | LocalDataFlow.cs:237:15:237:20 | access to local variable sink36 | +| LocalDataFlow.cs:236:9:236:14 | access to local variable sink36 | LocalDataFlow.cs:237:15:237:20 | access to local variable sink36 | +| LocalDataFlow.cs:236:27:236:32 | access to local variable sink35 | LocalDataFlow.cs:236:9:236:14 | access to local variable sink36 | +| LocalDataFlow.cs:240:13:240:51 | SSA def(nonSink10) | LocalDataFlow.cs:241:15:241:23 | access to local variable nonSink10 | +| LocalDataFlow.cs:240:25:240:51 | object creation of type StringBuilder | LocalDataFlow.cs:240:13:240:51 | SSA def(nonSink10) | +| LocalDataFlow.cs:240:43:240:50 | access to local variable nonSink0 | LocalDataFlow.cs:240:25:240:51 | object creation of type StringBuilder | +| LocalDataFlow.cs:241:15:241:23 | [post] access to local variable nonSink10 | LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | +| LocalDataFlow.cs:241:15:241:23 | access to local variable nonSink10 | LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | +| LocalDataFlow.cs:242:9:242:39 | SSA def(nonSink0) | LocalDataFlow.cs:243:15:243:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:242:20:242:28 | [post] access to local variable nonSink10 | LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | +| LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | LocalDataFlow.cs:242:20:242:39 | call to method ToString | +| LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | +| LocalDataFlow.cs:242:20:242:39 | call to method ToString | LocalDataFlow.cs:242:9:242:39 | SSA def(nonSink0) | +| LocalDataFlow.cs:243:15:243:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:244:30:244:37 | access to local variable nonSink0 | +| LocalDataFlow.cs:243:15:243:22 | access to local variable nonSink0 | LocalDataFlow.cs:244:30:244:37 | access to local variable nonSink0 | +| LocalDataFlow.cs:244:9:244:17 | [post] access to local variable nonSink10 | LocalDataFlow.cs:245:15:245:23 | access to local variable nonSink10 | +| LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | LocalDataFlow.cs:245:15:245:23 | access to local variable nonSink10 | +| LocalDataFlow.cs:244:30:244:37 | access to local variable nonSink0 | LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | +| LocalDataFlow.cs:248:13:248:52 | SSA def(taintedDataContract) | LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:248:13:248:52 | SSA qualifier def(taintedDataContract.AList) | LocalDataFlow.cs:251:22:251:46 | access to property AList | +| LocalDataFlow.cs:248:35:248:52 | object creation of type DataContract | LocalDataFlow.cs:248:13:248:52 | SSA def(taintedDataContract) | +| LocalDataFlow.cs:249:13:249:48 | SSA def(sink53) | LocalDataFlow.cs:250:15:250:20 | access to local variable sink53 | +| LocalDataFlow.cs:249:22:249:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | LocalDataFlow.cs:249:22:249:48 | access to property AString | +| LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:249:22:249:48 | access to property AString | LocalDataFlow.cs:249:13:249:48 | SSA def(sink53) | +| LocalDataFlow.cs:251:13:251:57 | SSA def(sink54) | LocalDataFlow.cs:252:15:252:20 | access to local variable sink54 | +| LocalDataFlow.cs:251:22:251:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:46 | access to property AList | +| LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:251:22:251:46 | [post] access to property AList | LocalDataFlow.cs:260:20:260:44 | access to property AList | +| LocalDataFlow.cs:251:22:251:46 | access to property AList | LocalDataFlow.cs:251:22:251:49 | access to indexer | +| LocalDataFlow.cs:251:22:251:46 | access to property AList | LocalDataFlow.cs:260:20:260:44 | access to property AList | +| LocalDataFlow.cs:251:22:251:49 | access to indexer | LocalDataFlow.cs:251:22:251:57 | access to property AString | +| LocalDataFlow.cs:251:22:251:57 | access to property AString | LocalDataFlow.cs:251:13:251:57 | SSA def(sink54) | +| LocalDataFlow.cs:255:13:255:55 | SSA def(nonTaintedDataContract) | LocalDataFlow.cs:256:20:256:41 | access to local variable nonTaintedDataContract | +| LocalDataFlow.cs:255:38:255:55 | object creation of type DataContract | LocalDataFlow.cs:255:13:255:55 | SSA def(nonTaintedDataContract) | +| LocalDataFlow.cs:256:9:256:49 | SSA def(nonSink0) | LocalDataFlow.cs:257:15:257:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:256:20:256:41 | access to local variable nonTaintedDataContract | LocalDataFlow.cs:256:20:256:49 | access to property AString | +| LocalDataFlow.cs:256:20:256:49 | access to property AString | LocalDataFlow.cs:256:9:256:49 | SSA def(nonSink0) | +| LocalDataFlow.cs:258:9:258:44 | SSA def(nonSink2) | LocalDataFlow.cs:259:15:259:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:258:20:258:38 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:258:20:258:44 | access to property AnInt | LocalDataFlow.cs:258:9:258:44 | SSA def(nonSink2) | +| LocalDataFlow.cs:260:9:260:53 | SSA def(nonSink2) | LocalDataFlow.cs:261:15:261:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:44 | access to property AList | +| LocalDataFlow.cs:260:20:260:44 | access to property AList | LocalDataFlow.cs:260:20:260:47 | access to indexer | +| LocalDataFlow.cs:260:20:260:53 | access to property AnInt | LocalDataFlow.cs:260:9:260:53 | SSA def(nonSink2) | +| LocalDataFlow.cs:264:17:264:37 | SSA def(taintedTextBox) | LocalDataFlow.cs:265:22:265:35 | access to local variable taintedTextBox | +| LocalDataFlow.cs:264:34:264:37 | null | LocalDataFlow.cs:264:17:264:37 | SSA def(taintedTextBox) | +| LocalDataFlow.cs:265:13:265:40 | SSA def(sink60) | LocalDataFlow.cs:266:15:266:20 | access to local variable sink60 | +| LocalDataFlow.cs:265:22:265:35 | access to local variable taintedTextBox | LocalDataFlow.cs:265:22:265:40 | access to property Text | +| LocalDataFlow.cs:265:22:265:40 | access to property Text | LocalDataFlow.cs:265:13:265:40 | SSA def(sink60) | +| LocalDataFlow.cs:269:17:269:40 | SSA def(nonTaintedTextBox) | LocalDataFlow.cs:270:20:270:36 | access to local variable nonTaintedTextBox | +| LocalDataFlow.cs:269:37:269:40 | null | LocalDataFlow.cs:269:17:269:40 | SSA def(nonTaintedTextBox) | +| LocalDataFlow.cs:270:9:270:41 | SSA def(nonSink0) | LocalDataFlow.cs:271:15:271:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:270:20:270:36 | access to local variable nonTaintedTextBox | LocalDataFlow.cs:270:20:270:41 | access to property Text | +| LocalDataFlow.cs:270:20:270:41 | access to property Text | LocalDataFlow.cs:270:9:270:41 | SSA def(nonSink0) | +| LocalDataFlow.cs:274:13:274:51 | SSA def(sink67) | LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | +| LocalDataFlow.cs:274:22:274:51 | call to method Run | LocalDataFlow.cs:274:13:274:51 | SSA def(sink67) | +| LocalDataFlow.cs:274:31:274:50 | [output] (...) => ... | LocalDataFlow.cs:274:22:274:51 | call to method Run | +| LocalDataFlow.cs:275:15:275:20 | [post] access to local variable sink67 | LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | +| LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | +| LocalDataFlow.cs:276:13:276:33 | SSA def(sink68) | LocalDataFlow.cs:277:15:277:20 | access to local variable sink68 | +| LocalDataFlow.cs:276:22:276:33 | await ... | LocalDataFlow.cs:276:13:276:33 | SSA def(sink68) | +| LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | LocalDataFlow.cs:276:22:276:33 | await ... | +| LocalDataFlow.cs:280:13:280:42 | SSA def(nonSink21) | LocalDataFlow.cs:281:15:281:23 | access to local variable nonSink21 | +| LocalDataFlow.cs:280:25:280:42 | call to method Run | LocalDataFlow.cs:280:13:280:42 | SSA def(nonSink21) | +| LocalDataFlow.cs:280:34:280:41 | [output] (...) => ... | LocalDataFlow.cs:280:25:280:42 | call to method Run | +| LocalDataFlow.cs:281:15:281:23 | [post] access to local variable nonSink21 | LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | +| LocalDataFlow.cs:281:15:281:23 | access to local variable nonSink21 | LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | +| LocalDataFlow.cs:282:9:282:34 | SSA def(nonSink0) | LocalDataFlow.cs:283:15:283:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:282:20:282:34 | await ... | LocalDataFlow.cs:282:9:282:34 | SSA def(nonSink0) | +| LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | LocalDataFlow.cs:282:20:282:34 | await ... | +| LocalDataFlow.cs:283:15:283:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:290:28:290:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:283:15:283:22 | access to local variable nonSink0 | LocalDataFlow.cs:290:28:290:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:286:13:286:36 | SSA def(sink69) | LocalDataFlow.cs:287:15:287:20 | access to local variable sink69 | +| LocalDataFlow.cs:286:22:286:36 | $"..." | LocalDataFlow.cs:286:13:286:36 | SSA def(sink69) | +| LocalDataFlow.cs:286:24:286:28 | "test " | LocalDataFlow.cs:286:22:286:36 | $"..." | +| LocalDataFlow.cs:286:30:286:34 | access to local variable sink1 | LocalDataFlow.cs:286:22:286:36 | $"..." | +| LocalDataFlow.cs:290:9:290:37 | SSA def(nonSink0) | LocalDataFlow.cs:291:15:291:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:290:20:290:37 | $"..." | LocalDataFlow.cs:290:9:290:37 | SSA def(nonSink0) | +| LocalDataFlow.cs:290:22:290:26 | "test " | LocalDataFlow.cs:290:20:290:37 | $"..." | +| LocalDataFlow.cs:290:28:290:35 | access to local variable nonSink0 | LocalDataFlow.cs:290:20:290:37 | $"..." | +| LocalDataFlow.cs:291:15:291:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:298:31:298:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:291:15:291:22 | access to local variable nonSink0 | LocalDataFlow.cs:298:31:298:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:294:13:294:34 | SSA def(sink70) | LocalDataFlow.cs:295:15:295:20 | access to local variable sink70 | +| LocalDataFlow.cs:294:22:294:34 | ... = ... | LocalDataFlow.cs:294:13:294:34 | SSA def(sink70) | +| LocalDataFlow.cs:294:22:294:34 | SSA def(sink0) | LocalDataFlow.cs:326:34:326:38 | access to local variable sink0 | +| LocalDataFlow.cs:294:22:294:34 | SSA def(sink0) | LocalDataFlow.cs:327:22:327:26 | access to local variable sink0 | +| LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | LocalDataFlow.cs:294:22:294:34 | ... = ... | +| LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | LocalDataFlow.cs:294:22:294:34 | SSA def(sink0) | +| LocalDataFlow.cs:295:15:295:20 | [post] access to local variable sink70 | LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | +| LocalDataFlow.cs:295:15:295:20 | access to local variable sink70 | LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | +| LocalDataFlow.cs:298:9:298:38 | SSA def(nonSink0) | LocalDataFlow.cs:299:15:299:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:298:20:298:38 | ... = ... | LocalDataFlow.cs:298:9:298:38 | SSA def(nonSink0) | +| LocalDataFlow.cs:298:31:298:38 | access to local variable nonSink0 | LocalDataFlow.cs:298:20:298:38 | ... = ... | +| LocalDataFlow.cs:299:15:299:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | +| LocalDataFlow.cs:299:15:299:22 | access to local variable nonSink0 | LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | +| LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | LocalDataFlow.cs:302:23:302:35 | SSA def(sink71) | +| LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | LocalDataFlow.cs:310:17:310:22 | access to local variable sink70 | +| LocalDataFlow.cs:302:23:302:35 | SSA def(sink71) | LocalDataFlow.cs:303:19:303:24 | access to local variable sink71 | +| LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | LocalDataFlow.cs:306:25:306:40 | SSA def(nonSink16) | +| LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | LocalDataFlow.cs:318:17:318:24 | access to local variable nonSink0 | +| LocalDataFlow.cs:306:25:306:40 | SSA def(nonSink16) | LocalDataFlow.cs:307:19:307:27 | access to local variable nonSink16 | +| LocalDataFlow.cs:310:17:310:22 | access to local variable sink70 | LocalDataFlow.cs:312:18:312:30 | SSA def(sink72) | +| LocalDataFlow.cs:312:18:312:30 | SSA def(sink72) | LocalDataFlow.cs:313:23:313:28 | access to local variable sink72 | +| LocalDataFlow.cs:318:17:318:24 | access to local variable nonSink0 | LocalDataFlow.cs:320:18:320:33 | SSA def(nonSink17) | +| LocalDataFlow.cs:318:17:318:24 | access to local variable nonSink0 | LocalDataFlow.cs:326:22:326:29 | access to local variable nonSink0 | +| LocalDataFlow.cs:320:18:320:33 | SSA def(nonSink17) | LocalDataFlow.cs:321:23:321:31 | access to local variable nonSink17 | +| LocalDataFlow.cs:326:13:326:38 | SSA def(sink73) | LocalDataFlow.cs:328:15:328:20 | access to local variable sink73 | +| LocalDataFlow.cs:326:22:326:29 | access to local variable nonSink0 | LocalDataFlow.cs:326:22:326:38 | ... ?? ... | +| LocalDataFlow.cs:326:22:326:29 | access to local variable nonSink0 | LocalDataFlow.cs:327:31:327:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:326:22:326:38 | ... ?? ... | LocalDataFlow.cs:326:13:326:38 | SSA def(sink73) | +| LocalDataFlow.cs:326:34:326:38 | access to local variable sink0 | LocalDataFlow.cs:326:22:326:38 | ... ?? ... | +| LocalDataFlow.cs:326:34:326:38 | access to local variable sink0 | LocalDataFlow.cs:327:22:327:26 | access to local variable sink0 | +| LocalDataFlow.cs:327:13:327:38 | SSA def(sink74) | LocalDataFlow.cs:329:15:329:20 | access to local variable sink74 | +| LocalDataFlow.cs:327:22:327:26 | access to local variable sink0 | LocalDataFlow.cs:327:22:327:38 | ... ?? ... | +| LocalDataFlow.cs:327:22:327:38 | ... ?? ... | LocalDataFlow.cs:327:13:327:38 | SSA def(sink74) | +| LocalDataFlow.cs:327:31:327:38 | access to local variable nonSink0 | LocalDataFlow.cs:327:22:327:38 | ... ?? ... | +| LocalDataFlow.cs:347:28:347:30 | this | LocalDataFlow.cs:347:41:347:45 | this access | +| LocalDataFlow.cs:347:50:347:52 | this | LocalDataFlow.cs:347:56:347:60 | this access | +| LocalDataFlow.cs:347:50:347:52 | value | LocalDataFlow.cs:347:50:347:52 | value | +| LocalDataFlow.cs:347:50:347:52 | value | LocalDataFlow.cs:347:64:347:68 | access to parameter value | +| LocalDataFlow.cs:353:41:353:47 | tainted | LocalDataFlow.cs:353:41:353:47 | tainted | +| LocalDataFlow.cs:353:41:353:47 | tainted | LocalDataFlow.cs:355:15:355:21 | access to parameter tainted | +| LocalDataFlow.cs:358:44:358:53 | nonTainted | LocalDataFlow.cs:358:44:358:53 | nonTainted | +| LocalDataFlow.cs:358:44:358:53 | nonTainted | LocalDataFlow.cs:360:15:360:24 | access to parameter nonTainted | +| LocalDataFlow.cs:363:44:363:44 | x | LocalDataFlow.cs:363:44:363:44 | x | +| LocalDataFlow.cs:363:44:363:44 | x | LocalDataFlow.cs:366:21:366:21 | access to parameter x | +| LocalDataFlow.cs:363:67:363:68 | os | LocalDataFlow.cs:363:67:363:68 | os | +| LocalDataFlow.cs:363:67:363:68 | os | LocalDataFlow.cs:369:32:369:33 | access to parameter os | +| LocalDataFlow.cs:366:21:366:21 | access to parameter x | LocalDataFlow.cs:366:16:366:21 | ... = ... | +| LocalDataFlow.cs:369:32:369:33 | access to parameter os | LocalDataFlow.cs:369:26:369:33 | ... = ... | +| LocalDataFlow.cs:374:41:374:44 | args | LocalDataFlow.cs:374:41:374:44 | args | +| LocalDataFlow.cs:374:41:374:44 | args | LocalDataFlow.cs:376:29:376:32 | access to parameter args | +| LocalDataFlow.cs:376:29:376:32 | [post] access to parameter args | LocalDataFlow.cs:377:27:377:30 | access to parameter args | +| LocalDataFlow.cs:376:29:376:32 | access to parameter args | LocalDataFlow.cs:376:29:376:32 | call to operator implicit conversion | +| LocalDataFlow.cs:376:29:376:32 | access to parameter args | LocalDataFlow.cs:377:27:377:30 | access to parameter args | | SSA.cs:5:17:5:17 | SSA entry def(this.S) | SSA.cs:67:9:67:14 | access to field S | | SSA.cs:5:17:5:17 | this | SSA.cs:67:9:67:12 | this access | | SSA.cs:5:26:5:32 | tainted | SSA.cs:5:26:5:32 | tainted | From d8dcbe3cbdf69593e81f0fa27da91669a12a6d6c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 14 Apr 2020 10:20:35 +0200 Subject: [PATCH 0119/1298] C++: QLDoc for FileClosed, LoopBounds and MemoryFreed --- cpp/ql/src/Critical/FileClosed.qll | 10 ++++++++++ cpp/ql/src/Critical/LoopBounds.qll | 11 +++++++++++ cpp/ql/src/Critical/MemoryFreed.qll | 9 +++++++++ 3 files changed, 30 insertions(+) diff --git a/cpp/ql/src/Critical/FileClosed.qll b/cpp/ql/src/Critical/FileClosed.qll index 1e782259156..a58af50ba67 100644 --- a/cpp/ql/src/Critical/FileClosed.qll +++ b/cpp/ql/src/Critical/FileClosed.qll @@ -1,5 +1,6 @@ import semmle.code.cpp.pointsto.PointsTo +/** Holds if there exists a call to a function that might close the file specified by `e`. */ predicate closed(Expr e) { fcloseCall(_, e) or exists(ExprCall c | @@ -8,10 +9,19 @@ predicate closed(Expr e) { ) } +/** An expression for which there exists a function call that might close it. */ class ClosedExpr extends PointsToExpr { ClosedExpr() { closed(this) } override predicate interesting() { closed(this) } } +/** + * Holds if `fc` is a call to function that opens a file which might be closed. For example: + * ``` + * FILE* f = fopen("file.txt", "r"); + * ... + * fclose(f); + * ``` + */ predicate fopenCallMayBeClosed(FunctionCall fc) { fopenCall(fc) and anythingPointsTo(fc) } diff --git a/cpp/ql/src/Critical/LoopBounds.qll b/cpp/ql/src/Critical/LoopBounds.qll index f10e62c909f..390655b004e 100644 --- a/cpp/ql/src/Critical/LoopBounds.qll +++ b/cpp/ql/src/Critical/LoopBounds.qll @@ -2,12 +2,23 @@ import cpp +/** An assignment to a variable with the value `0`. For example: + * ``` + * int x; + * x = 0; + * ``` + * but not: + * ``` + * int x = 0; + * ``` + */ class ZeroAssignment extends AssignExpr { ZeroAssignment() { this.getAnOperand() instanceof VariableAccess and this.getAnOperand() instanceof Zero } + /** Gets a variable that is assigned the value `0`. */ Variable assignedVariable() { result.getAnAccess() = this.getAnOperand() } } diff --git a/cpp/ql/src/Critical/MemoryFreed.qll b/cpp/ql/src/Critical/MemoryFreed.qll index 880199e54c9..44557503e43 100644 --- a/cpp/ql/src/Critical/MemoryFreed.qll +++ b/cpp/ql/src/Critical/MemoryFreed.qll @@ -9,10 +9,19 @@ private predicate freed(Expr e) { ) } +/** An expression that might be deallocated. */ class FreedExpr extends PointsToExpr { FreedExpr() { freed(this) } override predicate interesting() { freed(this) } } +/** + * An allocation expression that might be deallocated. For example: + * ``` + * int* p = new int; + * ... + * delete p; + * ``` + */ predicate allocMayBeFreed(AllocationExpr alloc) { anythingPointsTo(alloc) } From e47575ce5b3c676a1137abf8ba44d490f90f86be Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 14 Apr 2020 10:24:08 +0200 Subject: [PATCH 0120/1298] more precise getChild for matching "../" --- .../javascript/security/dataflow/TaintedPathCustomizations.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index 66708b4630e..9ec8473fc0a 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -285,7 +285,7 @@ module TaintedPath { exists(RegExpSequence seq | seq = result | seq.getChild(0).getConstantValue() = "." and seq.getChild(1).getConstantValue() = "." and - seq.getAChild().getAMatchedString() = "/" + seq.getChild(2).getAMatchedString() = "/" ) or exists(RegExpGroup group | result = group | group.getChild(0) = getADotDotSlashMatcher()) From 6827b84bdcbfb1c78063b4cf8e10d7687c4636c2 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 14 Apr 2020 10:32:16 +0200 Subject: [PATCH 0121/1298] change docstring to inline comment, and refer directly to array class --- javascript/ql/src/semmle/javascript/Collections.qll | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Collections.qll b/javascript/ql/src/semmle/javascript/Collections.qll index a0319391890..f6e4040ac7d 100644 --- a/javascript/ql/src/semmle/javascript/Collections.qll +++ b/javascript/ql/src/semmle/javascript/Collections.qll @@ -159,10 +159,9 @@ private module CollectionDataFlow { * A step for a `for of` statement on a Map, Set, or Iterator. * For Sets and iterators the l-value are the elements of the set/iterator. * For Maps the l-value is a tuple containing a key and a value. - * - * 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 `CollectionsTypeTracking`. */ + // This is partially duplicated behavior with the `for of` step for Arrays (`ArrayDataFlow::ForOfStep`). + // This duplication is required for the type-tracking steps defined in `CollectionsTypeTracking`. private class ForOfStep extends CollectionFlowStep, DataFlow::ValueNode { ForOfStmt forOf; DataFlow::Node element; From dc084628cc2bc612c0f3b92b0bba5acb2b7d22e8 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 9 Apr 2020 09:41:00 +0100 Subject: [PATCH 0122/1298] JS: Avoid the special name getURL --- javascript/ql/src/semmle/javascript/NPM.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/NPM.qll b/javascript/ql/src/semmle/javascript/NPM.qll index d82200bdf31..1038b04b6c2 100644 --- a/javascript/ql/src/semmle/javascript/NPM.qll +++ b/javascript/ql/src/semmle/javascript/NPM.qll @@ -190,7 +190,7 @@ class BugTrackerInfo extends JSONValue { } /** Gets the bug tracker URL. */ - string getURL() { + string getUrl() { result = this.(JSONObject).getPropStringValue("url") or result = this.(JSONString).getValue() } From 244a304e1d71152b239772b58be145bb44f87ec3 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 9 Apr 2020 09:57:31 +0100 Subject: [PATCH 0123/1298] JS: Implement getFile() directly instead of via locations --- .../semmle/javascript/dataflow/DataFlow.qll | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index d7bf1e304ea..b3b35142dd6 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -173,7 +173,7 @@ module DataFlow { } /** Gets the file this data flow node comes from. */ - File getFile() { hasLocationInfo(result.getAbsolutePath(), _, _, _, _) } + File getFile() { none() } // overridden in subclasses /** Gets the start line of this data flow node. */ int getStartLine() { hasLocationInfo(_, result, _, _, _) } @@ -313,6 +313,8 @@ module DataFlow { astNode.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) } + override File getFile() { result = astNode.getFile() } + override string toString() { result = astNode.toString() } } @@ -337,6 +339,8 @@ module DataFlow { override string toString() { result = ssa.getSourceVariable().getName() } + override File getFile() { result = ssa.getBasicBlock().getFile() } + override ASTNode getAstNode() { none() } } @@ -361,6 +365,8 @@ module DataFlow { override string toString() { result = prop.(ASTNode).toString() } + override File getFile() { result = prop.(ASTNode).getFile() } + override ASTNode getAstNode() { result = prop } } @@ -384,6 +390,8 @@ module DataFlow { override string toString() { result = "..." + rest.toString() } + override File getFile() { result = pattern.getFile() } + override ASTNode getAstNode() { result = rest } } @@ -406,6 +414,8 @@ module DataFlow { override string toString() { result = pattern.toString() } + override File getFile() { result = pattern.getFile() } + override ASTNode getAstNode() { result = pattern } } @@ -429,6 +439,8 @@ module DataFlow { override string toString() { result = elt.toString() } + override File getFile() { result = pattern.getFile() } + override ASTNode getAstNode() { result = elt } } @@ -456,6 +468,8 @@ module DataFlow { override string toString() { result = elt.toString() } + override File getFile() { result = arr.getFile() } + override ASTNode getAstNode() { result = elt } } @@ -478,6 +492,8 @@ module DataFlow { } override string toString() { result = "reflective call" } + + override File getFile() { result = call.getFile() } } /** @@ -497,6 +513,8 @@ module DataFlow { } override string toString() { result = imprt.toString() } + + override File getFile() { result = imprt.getFile() } } /** @@ -924,6 +942,8 @@ module DataFlow { ) { p.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) } + + override File getFile() { result = p.getFile() } } /** @@ -944,6 +964,8 @@ module DataFlow { /** Gets the attribute corresponding to this data flow node. */ HTML::Attribute getAttribute() { result = attr } + + override File getFile() { result = attr.getFile() } } /** @@ -968,6 +990,8 @@ module DataFlow { * Gets the function corresponding to this exceptional return node. */ Function getFunction() { result = function } + + override File getFile() { result = function.getFile() } } /** @@ -992,6 +1016,8 @@ module DataFlow { * Gets the invocation corresponding to this exceptional return node. */ DataFlow::InvokeNode getInvocation() { result = invoke.flow() } + + override File getFile() { result = invoke.getFile() } } /** @@ -1219,6 +1245,10 @@ module DataFlow { .hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) ) } + + override File getFile() { + exists(StmtContainer container | this = TThisNode(container) | result = container.getFile()) + } } /** From 5da968e34c46e9f560f6f89701ebd1f5dc6d819b Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 9 Apr 2020 10:47:15 +0100 Subject: [PATCH 0124/1298] JS: Specialize ASTNode.getFile --- javascript/ql/src/semmle/javascript/AST.qll | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/AST.qll b/javascript/ql/src/semmle/javascript/AST.qll index b1cbe224764..81bb64f272c 100644 --- a/javascript/ql/src/semmle/javascript/AST.qll +++ b/javascript/ql/src/semmle/javascript/AST.qll @@ -23,6 +23,10 @@ import javascript class ASTNode extends @ast_node, Locatable { override Location getLocation() { hasLocation(this, result) } + override File getFile() { + result = getLocation().getFile() // Specialized for performance reasons + } + /** Gets the first token belonging to this element. */ Token getFirstToken() { exists(Location l1, Location l2 | From 88667206fcf1d78503227e6db52187435dc906b1 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 9 Apr 2020 11:20:21 +0100 Subject: [PATCH 0125/1298] JS: Remove default hasLocationInfo case --- javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index b3b35142dd6..31ca34f1c0c 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -165,11 +165,7 @@ module DataFlow { predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn ) { - filepath = "" and - startline = 0 and - startcolumn = 0 and - endline = 0 and - endcolumn = 0 + none() } /** Gets the file this data flow node comes from. */ From 3515a2b412c169c3b9966c3217ad38e6f3f8856e Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 14 Apr 2020 10:31:31 +0100 Subject: [PATCH 0126/1298] JS: Update test output --- .../Refinement_getRefinedVar.expected | 4 +- .../SSA/GetRhsNode/GetRhsNode.expected | 28 +++--- .../AngularJS/modules/ModuleRef.expected | 24 ++--- .../variables/getDeclaringContainer.expected | 92 +++++++++---------- 4 files changed, 74 insertions(+), 74 deletions(-) diff --git a/javascript/ql/test/library-tests/Refinements/Refinement_getRefinedVar.expected b/javascript/ql/test/library-tests/Refinements/Refinement_getRefinedVar.expected index fcb1b6cbba0..6673b6e7cb3 100644 --- a/javascript/ql/test/library-tests/Refinements/Refinement_getRefinedVar.expected +++ b/javascript/ql/test/library-tests/Refinements/Refinement_getRefinedVar.expected @@ -1,2 +1,2 @@ -| tst.js:4:3:4:27 | (typeof ... nction' | x | -| tst.js:8:3:8:23 | (typeof ... === 'u' | x | +| tst.js:4:3:4:27 | (typeof ... nction' | tst.js:3:12:3:12 | x | +| tst.js:8:3:8:23 | (typeof ... === 'u' | tst.js:3:12:3:12 | x | diff --git a/javascript/ql/test/library-tests/SSA/GetRhsNode/GetRhsNode.expected b/javascript/ql/test/library-tests/SSA/GetRhsNode/GetRhsNode.expected index 7f37d2d2a11..e971020cdd6 100644 --- a/javascript/ql/test/library-tests/SSA/GetRhsNode/GetRhsNode.expected +++ b/javascript/ql/test/library-tests/SSA/GetRhsNode/GetRhsNode.expected @@ -1,14 +1,14 @@ -| tst.js:2:7:2:13 | a = g() | a | tst.js:2:11:2:13 | g() | -| tst.js:4:7:4:24 | { propB: b } = g() | b | tst.js:4:9:4:16 | propB: b | -| tst.js:6:7:6:34 | { propC ... } = g() | c | tst.js:6:9:6:16 | propC: c | -| tst.js:6:7:6:34 | { propC ... } = g() | d | tst.js:6:19:6:26 | propD: d | -| tst.js:8:7:8:41 | { array ... } = g() | elm1 | tst.js:8:22:8:25 | elm1 | -| tst.js:8:7:8:41 | { array ... } = g() | elm2 | tst.js:8:28:8:31 | elm2 | -| tst.js:17:3:17:22 | ({ propB: b }) = g() | b | tst.js:17:6:17:13 | propB: b | -| tst.js:19:3:19:32 | ({ prop ... ) = g() | c | tst.js:19:6:19:13 | propC: c | -| tst.js:19:3:19:32 | ({ prop ... ) = g() | d | tst.js:19:16:19:23 | propD: d | -| tst.js:21:3:21:22 | [ elm1, elm2 ] = g() | elm1 | tst.js:21:5:21:8 | elm1 | -| tst.js:21:3:21:22 | [ elm1, elm2 ] = g() | elm2 | tst.js:21:11:21:14 | elm2 | -| tst.js:31:12:31:23 | [elm1, elm2] | elm1 | tst.js:31:13:31:16 | elm1 | -| tst.js:31:12:31:23 | [elm1, elm2] | elm2 | tst.js:31:19:31:22 | elm2 | -| tst.js:31:26:31:40 | { prop: value } | value | tst.js:31:28:31:38 | prop: value | +| tst.js:2:7:2:13 | a = g() | tst.js:2:7:2:7 | a | tst.js:2:11:2:13 | g() | +| tst.js:4:7:4:24 | { propB: b } = g() | tst.js:4:16:4:16 | b | tst.js:4:9:4:16 | propB: b | +| tst.js:6:7:6:34 | { propC ... } = g() | tst.js:6:16:6:16 | c | tst.js:6:9:6:16 | propC: c | +| tst.js:6:7:6:34 | { propC ... } = g() | tst.js:6:26:6:26 | d | tst.js:6:19:6:26 | propD: d | +| tst.js:8:7:8:41 | { array ... } = g() | tst.js:8:22:8:25 | elm1 | tst.js:8:22:8:25 | elm1 | +| tst.js:8:7:8:41 | { array ... } = g() | tst.js:8:28:8:31 | elm2 | tst.js:8:28:8:31 | elm2 | +| tst.js:17:3:17:22 | ({ propB: b }) = g() | tst.js:4:16:4:16 | b | tst.js:17:6:17:13 | propB: b | +| tst.js:19:3:19:32 | ({ prop ... ) = g() | tst.js:6:16:6:16 | c | tst.js:19:6:19:13 | propC: c | +| tst.js:19:3:19:32 | ({ prop ... ) = g() | tst.js:6:26:6:26 | d | tst.js:19:16:19:23 | propD: d | +| tst.js:21:3:21:22 | [ elm1, elm2 ] = g() | tst.js:8:22:8:25 | elm1 | tst.js:21:5:21:8 | elm1 | +| tst.js:21:3:21:22 | [ elm1, elm2 ] = g() | tst.js:8:28:8:31 | elm2 | tst.js:21:11:21:14 | elm2 | +| tst.js:31:12:31:23 | [elm1, elm2] | tst.js:31:13:31:16 | elm1 | tst.js:31:13:31:16 | elm1 | +| tst.js:31:12:31:23 | [elm1, elm2] | tst.js:31:19:31:22 | elm2 | tst.js:31:19:31:22 | elm2 | +| tst.js:31:26:31:40 | { prop: value } | tst.js:31:34:31:38 | value | tst.js:31:28:31:38 | prop: value | diff --git a/javascript/ql/test/library-tests/frameworks/AngularJS/modules/ModuleRef.expected b/javascript/ql/test/library-tests/frameworks/AngularJS/modules/ModuleRef.expected index bb82e314424..08ec97d5a9d 100644 --- a/javascript/ql/test/library-tests/frameworks/AngularJS/modules/ModuleRef.expected +++ b/javascript/ql/test/library-tests/frameworks/AngularJS/modules/ModuleRef.expected @@ -1,12 +1,12 @@ -| cm1 | -| cm2 | -| cm3 | -| cm4 | -| cm5 | -| cm6 | -| cm7 | -| cm8 | -| dm1 | -| m | -| mcm1 | -| rm1 | +| module-refs.js:3:9:3:11 | dm1 | +| module-refs.js:6:9:6:11 | rm1 | +| module-refs.js:9:9:9:11 | cm1 | +| module-refs.js:10:9:10:11 | cm2 | +| module-refs.js:11:9:11:11 | cm3 | +| module-refs.js:12:9:12:11 | cm4 | +| module-refs.js:13:9:13:11 | cm5 | +| module-refs.js:14:9:14:11 | cm6 | +| module-refs.js:15:9:15:11 | cm7 | +| module-refs.js:16:9:16:11 | cm8 | +| module-refs.js:22:9:22:12 | mcm1 | +| tst.js:19:7:19:7 | m | diff --git a/javascript/ql/test/library-tests/variables/getDeclaringContainer.expected b/javascript/ql/test/library-tests/variables/getDeclaringContainer.expected index bf97e07b559..b9013913d10 100644 --- a/javascript/ql/test/library-tests/variables/getDeclaringContainer.expected +++ b/javascript/ql/test/library-tests/variables/getDeclaringContainer.expected @@ -1,46 +1,46 @@ -| arguments | arrayPatternDefault.js:1:2:4:1 | functio ... bal2;\\n} | -| arguments | assignments.js:3:1:6:1 | functio ... = 56;\\n} | -| arguments | assignments.js:4:10:4:24 | function h() {} | -| arguments | defaultargs.js:1:2:5:1 | functio ... ]) {}\\n} | -| arguments | defaultargs.js:3:3:3:25 | functio ... = x) {} | -| arguments | defaultargs.js:4:3:4:51 | functio ... [0]) {} | -| arguments | for.js:1:2:5:1 | functio ... x;\\n} | -| arguments | let.js:14:1:21:1 | functio ... }\\n} | -| arguments | typeoftype.ts:1:1:6:1 | functio ... x\\n }\\n} | -| arguments | typeoftype.ts:3:3:5:3 | functio ... e x\\n } | -| arguments | variables.js:8:1:12:1 | functio ... ar x;\\n} | -| arguments | variables.js:13:1:23:1 | functio ... z;\\n\\t}\\n} | -| arguments | variables.js:16:2:22:2 | functio ... y+z;\\n\\t} | -| f | defaultargs.js:1:2:5:1 | functio ... ]) {}\\n} | -| g | assignments.js:3:1:6:1 | functio ... = 56;\\n} | -| g | defaultargs.js:1:2:5:1 | functio ... ]) {}\\n} | -| g | typeoftype.ts:1:1:6:1 | functio ... x\\n }\\n} | -| h | assignments.js:4:10:4:24 | function h() {} | -| h | variables.js:13:1:23:1 | functio ... z;\\n\\t}\\n} | -| o | arrayPatternDefault.js:1:2:4:1 | functio ... bal2;\\n} | -| o | for.js:1:2:5:1 | functio ... x;\\n} | -| x | arrayPatternDefault.js:1:2:4:1 | functio ... bal2;\\n} | -| x | defaultargs.js:1:2:5:1 | functio ... ]) {}\\n} | -| x | defaultargs.js:3:3:3:25 | functio ... = x) {} | -| x | defaultargs.js:4:3:4:51 | functio ... [0]) {} | -| x | for.js:1:2:5:1 | functio ... x;\\n} | -| x | legacyletstmt.js:1:1:8:0 | | -| x | let.js:1:1:22:0 | | -| x | let.js:1:1:22:0 | | -| x | let.js:1:1:22:0 | | -| x | let.js:1:1:22:0 | | -| x | let.js:1:1:22:0 | | -| x | let.js:14:1:21:1 | functio ... }\\n} | -| x | typeoftype.ts:1:1:6:1 | functio ... x\\n }\\n} | -| x | variables.js:8:1:12:1 | functio ... ar x;\\n} | -| x | variables.js:13:1:23:1 | functio ... z;\\n\\t}\\n} | -| y | defaultargs.js:3:3:3:25 | functio ... = x) {} | -| y | defaultargs.js:4:3:4:51 | functio ... [0]) {} | -| y | legacyletstmt.js:1:1:8:0 | | -| y | let.js:1:1:22:0 | | -| y | let.js:14:1:21:1 | functio ... }\\n} | -| y | typeoftype.ts:3:3:5:3 | functio ... e x\\n } | -| y | variables.js:13:1:23:1 | functio ... z;\\n\\t}\\n} | -| y | variables.js:16:2:22:2 | functio ... y+z;\\n\\t} | -| z | variables.js:13:1:23:1 | functio ... z;\\n\\t}\\n} | -| z | variables.js:16:2:22:2 | functio ... y+z;\\n\\t} | +| arrayPatternDefault.js:1:2:1:1 | arguments | arrayPatternDefault.js:1:2:4:1 | functio ... bal2;\\n} | +| arrayPatternDefault.js:1:11:1:11 | o | arrayPatternDefault.js:1:2:4:1 | functio ... bal2;\\n} | +| arrayPatternDefault.js:2:8:2:8 | x | arrayPatternDefault.js:1:2:4:1 | functio ... bal2;\\n} | +| assignments.js:3:1:3:0 | arguments | assignments.js:3:1:6:1 | functio ... = 56;\\n} | +| assignments.js:4:6:4:6 | g | assignments.js:3:1:6:1 | functio ... = 56;\\n} | +| assignments.js:4:10:4:9 | arguments | assignments.js:4:10:4:24 | function h() {} | +| assignments.js:4:19:4:19 | h | assignments.js:4:10:4:24 | function h() {} | +| defaultargs.js:2:7:2:7 | x | defaultargs.js:1:2:5:1 | functio ... ]) {}\\n} | +| defaultargs.js:2:10:2:18 | arguments | defaultargs.js:1:2:5:1 | functio ... ]) {}\\n} | +| defaultargs.js:3:3:3:2 | arguments | defaultargs.js:3:3:3:25 | functio ... = x) {} | +| defaultargs.js:3:12:3:12 | f | defaultargs.js:1:2:5:1 | functio ... ]) {}\\n} | +| defaultargs.js:3:14:3:14 | x | defaultargs.js:3:3:3:25 | functio ... = x) {} | +| defaultargs.js:3:17:3:17 | y | defaultargs.js:3:3:3:25 | functio ... = x) {} | +| defaultargs.js:4:3:4:2 | arguments | defaultargs.js:4:3:4:51 | functio ... [0]) {} | +| defaultargs.js:4:12:4:12 | g | defaultargs.js:1:2:5:1 | functio ... ]) {}\\n} | +| defaultargs.js:4:14:4:14 | x | defaultargs.js:4:3:4:51 | functio ... [0]) {} | +| defaultargs.js:4:32:4:32 | y | defaultargs.js:4:3:4:51 | functio ... [0]) {} | +| for.js:1:2:1:1 | arguments | for.js:1:2:5:1 | functio ... x;\\n} | +| for.js:1:11:1:11 | o | for.js:1:2:5:1 | functio ... x;\\n} | +| for.js:2:7:2:7 | x | for.js:1:2:5:1 | functio ... x;\\n} | +| legacyletstmt.js:3:6:3:6 | x | legacyletstmt.js:1:1:8:0 | | +| legacyletstmt.js:3:14:3:14 | y | legacyletstmt.js:1:1:8:0 | | +| let.js:2:9:2:9 | x | let.js:1:1:22:0 | | +| let.js:4:13:4:13 | x | let.js:1:1:22:0 | | +| let.js:5:18:5:18 | x | let.js:1:1:22:0 | | +| let.js:5:26:5:26 | y | let.js:1:1:22:0 | | +| let.js:6:17:6:17 | x | let.js:1:1:22:0 | | +| let.js:9:18:9:18 | x | let.js:1:1:22:0 | | +| let.js:14:1:14:0 | arguments | let.js:14:1:21:1 | functio ... }\\n} | +| let.js:14:14:14:14 | x | let.js:14:1:21:1 | functio ... }\\n} | +| let.js:17:11:17:11 | y | let.js:14:1:21:1 | functio ... }\\n} | +| typeoftype.ts:1:1:1:0 | arguments | typeoftype.ts:1:1:6:1 | functio ... x\\n }\\n} | +| typeoftype.ts:2:7:2:7 | x | typeoftype.ts:1:1:6:1 | functio ... x\\n }\\n} | +| typeoftype.ts:3:3:3:2 | arguments | typeoftype.ts:3:3:5:3 | functio ... e x\\n } | +| typeoftype.ts:3:12:3:12 | g | typeoftype.ts:1:1:6:1 | functio ... x\\n }\\n} | +| typeoftype.ts:4:9:4:9 | y | typeoftype.ts:3:3:5:3 | functio ... e x\\n } | +| variables.js:8:1:8:0 | arguments | variables.js:8:1:12:1 | functio ... ar x;\\n} | +| variables.js:9:6:9:6 | x | variables.js:8:1:12:1 | functio ... ar x;\\n} | +| variables.js:13:1:13:0 | arguments | variables.js:13:1:23:1 | functio ... z;\\n\\t}\\n} | +| variables.js:13:12:13:12 | y | variables.js:13:1:23:1 | functio ... z;\\n\\t}\\n} | +| variables.js:13:15:13:15 | z | variables.js:13:1:23:1 | functio ... z;\\n\\t}\\n} | +| variables.js:15:6:15:6 | x | variables.js:13:1:23:1 | functio ... z;\\n\\t}\\n} | +| variables.js:16:2:16:1 | arguments | variables.js:16:2:22:2 | functio ... y+z;\\n\\t} | +| variables.js:16:11:16:11 | h | variables.js:13:1:23:1 | functio ... z;\\n\\t}\\n} | +| variables.js:16:13:16:13 | z | variables.js:16:2:22:2 | functio ... y+z;\\n\\t} | +| variables.js:18:11:18:11 | y | variables.js:16:2:22:2 | functio ... y+z;\\n\\t} | From 419b511ddbca96875d6c72c1774930514508527d Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 14 Apr 2020 11:39:44 +0200 Subject: [PATCH 0127/1298] C++: Format --- cpp/ql/src/Critical/LoopBounds.qll | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/cpp/ql/src/Critical/LoopBounds.qll b/cpp/ql/src/Critical/LoopBounds.qll index 390655b004e..b2cde8d6fe8 100644 --- a/cpp/ql/src/Critical/LoopBounds.qll +++ b/cpp/ql/src/Critical/LoopBounds.qll @@ -2,15 +2,16 @@ import cpp -/** An assignment to a variable with the value `0`. For example: - * ``` - * int x; - * x = 0; - * ``` - * but not: - * ``` - * int x = 0; - * ``` +/** + * An assignment to a variable with the value `0`. For example: + * ``` + * int x; + * x = 0; + * ``` + * but not: + * ``` + * int x = 0; + * ``` */ class ZeroAssignment extends AssignExpr { ZeroAssignment() { From 92187d9e7189cd4bacb302202780eca932003c88 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 9 Apr 2020 17:45:38 +0100 Subject: [PATCH 0128/1298] C++: Change note. --- change-notes/1.24/analysis-cpp.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.24/analysis-cpp.md b/change-notes/1.24/analysis-cpp.md index 7ab002857cf..8f8c3d5364a 100644 --- a/change-notes/1.24/analysis-cpp.md +++ b/change-notes/1.24/analysis-cpp.md @@ -25,6 +25,7 @@ The following changes in version 1.24 affect C/C++ analysis in all applications. | Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) | | This query is no longer run on LGTM. | | No space for zero terminator (`cpp/no-space-for-terminator`) | Fewer false positive results | This query has been modified to be more conservative when identifying which pointers point to null-terminated strings. This approach produces fewer, more accurate results. | | Overflow in uncontrolled allocation size (`cpp/uncontrolled-allocation-size`) | Fewer false positive results | Cases where the tainted allocation size is range checked are now more reliably excluded. | +| Overflow in uncontrolled allocation size (`cpp/uncontrolled-allocation-size`) | Fewer false positive results | The query now produces fewer, more accurate results. | | Overloaded assignment does not return 'this' (`cpp/assignment-does-not-return-this`) | Fewer false positive results | This query no longer reports incorrect results in template classes. | | Unsafe array for days of the year (`cpp/leap-year/unsafe-array-for-days-of-the-year`) | | This query is no longer run on LGTM. | | Unsigned comparison to zero (`cpp/unsigned-comparison-zero`) | More correct results | This query now also looks for comparisons of the form `0 <= x`. | From c178eecd43a4fe84285c958e327fb75383798b90 Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 14 Apr 2020 14:40:21 +0100 Subject: [PATCH 0129/1298] Update javascript/ql/src/semmle/javascript/Variables.qll Co-Authored-By: Erik Krogh Kristensen --- 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 ede33788841..2cbd54d1d73 100644 --- a/javascript/ql/src/semmle/javascript/Variables.qll +++ b/javascript/ql/src/semmle/javascript/Variables.qll @@ -321,8 +321,8 @@ 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 entry point of its declaring container is used. + * If the variable has one or more declarations, the location of the first declaration is used. + * If the variable has no declaration, the entry point of its declaring container is used. */ Location getLocation() { result = From 83cd78c6cf84bf8a10e6ae1ffd19be61104ae142 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Tue, 14 Apr 2020 10:54:00 -0400 Subject: [PATCH 0130/1298] C++: Fix test output --- cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected | 1 + cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected | 1 + .../test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected | 1 + 3 files changed, 3 insertions(+) diff --git a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected index 362983363cc..fd988023d9a 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected @@ -539,6 +539,7 @@ unexplainedLoop | range_analysis.c:355:14:355:27 | test_ternary01 | range_analysis.c:367:10:367:10 | Load: x | | range_analysis.c:355:14:355:27 | test_ternary01 | range_analysis.c:367:10:367:10 | VariableAddress: x | unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled operandAcrossFunctions instructionWithoutUniqueBlock containsLoopOfForwardEdges diff --git a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected index cd5366a0c73..cec5ca7d9ed 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected @@ -596,6 +596,7 @@ unexplainedLoop | range_analysis.c:355:14:355:27 | test_ternary01 | range_analysis.c:367:10:367:10 | Load: x | | range_analysis.c:355:14:355:27 | test_ternary01 | range_analysis.c:367:10:367:10 | VariableAddress: x | unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled operandAcrossFunctions instructionWithoutUniqueBlock containsLoopOfForwardEdges diff --git a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected index 82b5f5ccef0..3a6083ec684 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected @@ -548,6 +548,7 @@ unexplainedLoop | range_analysis.c:355:14:355:27 | test_ternary01 | range_analysis.c:367:10:367:10 | Load: x | | range_analysis.c:355:14:355:27 | test_ternary01 | range_analysis.c:367:10:367:10 | VariableAddress: x | unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled operandAcrossFunctions instructionWithoutUniqueBlock containsLoopOfForwardEdges From 6668a7a546a0b84cda4cea24f2262907dee62fea Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 14 Apr 2020 10:01:27 +0100 Subject: [PATCH 0131/1298] JS: Add backwards-compatible predicates to SocketIO --- .../semmle/javascript/frameworks/SocketIO.qll | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/frameworks/SocketIO.qll b/javascript/ql/src/semmle/javascript/frameworks/SocketIO.qll index 45a58f9ec26..490f44fc758 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/SocketIO.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/SocketIO.qll @@ -82,6 +82,13 @@ module SocketIO { } override DataFlow::SourceNode ref() { result = server(DataFlow::TypeTracker::end()) } + + /** + * DEPRECATED. Always returns `this` as a `ServerObject` now represents the origin of a server. + * + * Instead of `getOrigin()` to get a server origin from a reference, use `ServerObject.ref()` to get references to a given server. + */ + deprecated DataFlow::SourceNode getOrigin() { result = this } } /** A data flow node that may produce (that is, create or return) a socket.io server. */ @@ -270,6 +277,21 @@ module SocketIO { } override string getChannel() { this.getArgument(0).mayHaveStringValue(result) } + + /** Gets a parameter through which data is received from a client. */ + DataFlow::SourceNode getAReceivedItem() { result = getReceivedItem(_) } + + /** Gets a client-side node that may be sending the data received here. */ + SendNode getASender() { result.getAReceiver() = this } + + /** Gets the acknowledgment callback, if any. */ + DataFlow::FunctionNode getAck() { + result = getListener().getLastParameter() and + exists(result.getAnInvocation()) + } + + /** DEPRECATED. Use `getChannel()` instead. */ + deprecated string getEventName() { result = getChannel() } } /** An acknowledgment callback when receiving a message. */ @@ -350,6 +372,16 @@ module SocketIO { override SocketIOClient::ReceiveNode getAReceiver() { result.getSocket().getATargetNamespace() = getNamespace() } + + /** Gets the acknowledgment callback, if any. */ + DataFlow::FunctionNode getAck() { + // acknowledgments are only available when sending through a socket + exists(getSocket()) and + result = getLastArgument().getALocalSource() + } + + /** DEPRECATED. Use `getChannel()` instead. */ + deprecated string getEventName() { result = getChannel() } } /** A socket.io namespace, identified by its server and its path. */ @@ -538,6 +570,21 @@ module SocketIOClient { result != cb.getLastParameter() or not exists(result.getAnInvocation()) ) } + + /** Gets a data flow node representing data received from the server. */ + DataFlow::SourceNode getAReceivedItem() { result = getReceivedItem(_) } + + /** Gets the acknowledgment callback, if any. */ + DataFlow::FunctionNode getAck() { + result = getListener().getLastParameter() and + exists(result.getAnInvocation()) + } + + /** Gets a server-side node that may be sending the data received here. */ + SocketIO::SendNode getASender() { + result.getNamespace() = getSocket().getATargetNamespace() and + not result.getChannel() != getChannel() + } } /** An acknowledgment callback from a receive node. */ @@ -607,10 +654,23 @@ module SocketIOClient { ) } + /** Gets a data flow node representing data sent to the client. */ + DataFlow::Node getASentItem() { result = getSentItem(_) } + /** Gets a server-side node that may be receiving the data sent here. */ override SocketIO::ReceiveNode getAReceiver() { result.getSocket().getNamespace() = getSocket().getATargetNamespace() } + + /** Gets the acknowledgment callback, if any. */ + DataFlow::FunctionNode getAck() { + // acknowledgments are only available when sending through a socket + exists(getSocket()) and + result = getLastArgument().getALocalSource() + } + + /** DEPRECATED. Use `getChannel()` instead. */ + deprecated string getEventName() { result = getChannel() } } /** From 95a6dd01c6207d624a9d501ebbe325f2e309f751 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Tue, 14 Apr 2020 11:11:36 -0400 Subject: [PATCH 0132/1298] C#: Accept test output --- csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected | 1 + csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected | 1 + 2 files changed, 2 insertions(+) diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected b/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected index c5a0b98598f..61bc9b2261c 100644 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected +++ b/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected @@ -9,6 +9,7 @@ instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled operandAcrossFunctions instructionWithoutUniqueBlock containsLoopOfForwardEdges diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected index c5a0b98598f..61bc9b2261c 100644 --- a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected +++ b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected @@ -9,6 +9,7 @@ instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled operandAcrossFunctions instructionWithoutUniqueBlock containsLoopOfForwardEdges From 125a09ce6e2e1e3e10ec5d0cc2bfb6cd54bcc924 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Tue, 14 Apr 2020 11:40:33 -0400 Subject: [PATCH 0133/1298] C++: Fix IR generation of `return` of `void` expression --- .../raw/internal/TranslatedStmt.qll | 37 ++++++++++++++++++- .../library-tests/ir/ir/PrintAST.expected | 17 +++++++++ cpp/ql/test/library-tests/ir/ir/ir.cpp | 4 ++ .../test/library-tests/ir/ir/raw_ir.expected | 23 ++++++++++++ 4 files changed, 80 insertions(+), 1 deletion(-) 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 f7d060c7c64..a4c9d487437 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 @@ -135,7 +135,7 @@ abstract class TranslatedReturnStmt extends TranslatedStmt { * The IR translation of a `return` statement that returns a value. */ class TranslatedReturnValueStmt extends TranslatedReturnStmt, TranslatedVariableInitialization { - TranslatedReturnValueStmt() { stmt.hasExpr() } + TranslatedReturnValueStmt() { stmt.hasExpr() and hasReturnValue(stmt.getEnclosingFunction()) } final override Instruction getInitializationSuccessor() { result = getEnclosingFunction().getReturnSuccessorInstruction() @@ -150,6 +150,41 @@ class TranslatedReturnValueStmt extends TranslatedReturnStmt, TranslatedVariable final override IRVariable getIRVariable() { result = getEnclosingFunction().getReturnVariable() } } +/** + * The IR translation of a `return` statement that returns an expression of `void` type. + */ +class TranslatedReturnVoidExpressionStmt extends TranslatedReturnStmt { + TranslatedReturnVoidExpressionStmt() { + stmt.hasExpr() and not hasReturnValue(stmt.getEnclosingFunction()) + } + + override TranslatedElement getChild(int id) { + id = 0 and + result = getExpr() + } + + override Instruction getFirstInstruction() { result = getExpr().getFirstInstruction() } + + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { + tag = OnlyInstructionTag() and + opcode instanceof Opcode::NoOp and + resultType = getVoidType() + } + + override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { + tag = OnlyInstructionTag() and + result = getEnclosingFunction().getReturnSuccessorInstruction() and + kind instanceof GotoEdge + } + + override Instruction getChildSuccessor(TranslatedElement child) { + child = getExpr() and + result = getInstruction(OnlyInstructionTag()) + } + + private TranslatedExpr getExpr() { result = getTranslatedExpr(stmt.getExpr()) } +} + /** * 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. diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected index e2a02352f0f..268371ab3d5 100644 --- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected +++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected @@ -8767,6 +8767,23 @@ ir.cpp: # 1291| Type = [IntType] int # 1291| ValueCategory = prvalue(load) # 1293| 1: [ReturnStmt] return ... +# 1295| [TopLevelFunction] void returnVoid(int, int) +# 1295| params: +# 1295| 0: [Parameter] x +# 1295| Type = [IntType] int +# 1295| 1: [Parameter] y +# 1295| Type = [IntType] int +# 1295| body: [Block] { ... } +# 1296| 0: [ReturnStmt] return ... +# 1296| 0: [FunctionCall] call to IntegerOps +# 1296| Type = [VoidType] void +# 1296| ValueCategory = prvalue +# 1296| 0: [VariableAccess] x +# 1296| Type = [IntType] int +# 1296| ValueCategory = prvalue(load) +# 1296| 1: [VariableAccess] y +# 1296| Type = [IntType] int +# 1296| ValueCategory = prvalue(load) 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 e40c4c095d6..cdebee29aea 100644 --- a/cpp/ql/test/library-tests/ir/ir/ir.cpp +++ b/cpp/ql/test/library-tests/ir/ir/ir.cpp @@ -1292,4 +1292,8 @@ int missingReturnValue(bool b, int x) { } } +void returnVoid(int x, int y) { + return IntegerOps(x, y); +} + // 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 344269ec7db..bc5fbd5b4d2 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -6661,6 +6661,29 @@ ir.cpp: # 1289| v1289_12(void) = AliasedUse : ~mu1289_4 # 1289| v1289_13(void) = ExitFunction : +# 1295| void returnVoid(int, int) +# 1295| Block 0 +# 1295| v1295_1(void) = EnterFunction : +# 1295| mu1295_2(unknown) = AliasedDefinition : +# 1295| mu1295_3(unknown) = InitializeNonLocal : +# 1295| mu1295_4(unknown) = UnmodeledDefinition : +# 1295| r1295_5(glval) = VariableAddress[x] : +# 1295| mu1295_6(int) = InitializeParameter[x] : &:r1295_5 +# 1295| r1295_7(glval) = VariableAddress[y] : +# 1295| mu1295_8(int) = InitializeParameter[y] : &:r1295_7 +# 1296| r1296_1(glval) = FunctionAddress[IntegerOps] : +# 1296| r1296_2(glval) = VariableAddress[x] : +# 1296| r1296_3(int) = Load : &:r1296_2, ~mu1295_4 +# 1296| r1296_4(glval) = VariableAddress[y] : +# 1296| r1296_5(int) = Load : &:r1296_4, ~mu1295_4 +# 1296| v1296_6(void) = Call : func:r1296_1, 0:r1296_3, 1:r1296_5 +# 1296| mu1296_7(unknown) = ^CallSideEffect : ~mu1295_4 +# 1296| v1296_8(void) = NoOp : +# 1295| v1295_9(void) = ReturnVoid : +# 1295| v1295_10(void) = UnmodeledUse : mu* +# 1295| v1295_11(void) = AliasedUse : ~mu1295_4 +# 1295| v1295_12(void) = ExitFunction : + perf-regression.cpp: # 6| void Big::Big() # 6| Block 0 From 092145d5712b1573242e160db20ac164030fa21b Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 14 Apr 2020 18:38:33 +0200 Subject: [PATCH 0134/1298] Update cpp/ql/src/Critical/FileClosed.qll Co-Authored-By: Jonas Jensen --- cpp/ql/src/Critical/FileClosed.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/Critical/FileClosed.qll b/cpp/ql/src/Critical/FileClosed.qll index a58af50ba67..e2ba3c25b81 100644 --- a/cpp/ql/src/Critical/FileClosed.qll +++ b/cpp/ql/src/Critical/FileClosed.qll @@ -17,7 +17,7 @@ class ClosedExpr extends PointsToExpr { } /** - * Holds if `fc` is a call to function that opens a file which might be closed. For example: + * Holds if `fc` is a call to a function that opens a file that might be closed. For example: * ``` * FILE* f = fopen("file.txt", "r"); * ... From 7f5b3de6657c9b845259ff3504a10d787b2220b0 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Tue, 14 Apr 2020 10:36:53 -0700 Subject: [PATCH 0135/1298] C++: autoformat --- cpp/ql/src/semmle/code/cpp/Comments.qll | 2 -- 1 file changed, 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Comments.qll b/cpp/ql/src/semmle/code/cpp/Comments.qll index 1558bf95477..7f961bfd6f6 100644 --- a/cpp/ql/src/semmle/code/cpp/Comments.qll +++ b/cpp/ql/src/semmle/code/cpp/Comments.qll @@ -1,5 +1,3 @@ - - import semmle.code.cpp.Location import semmle.code.cpp.Element From 5ee60762fef3897a15ac8c0f7ab8aab84ca5f925 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Tue, 14 Apr 2020 10:49:52 -0700 Subject: [PATCH 0136/1298] C++: deprecate Declaration::isDefined() --- cpp/ql/src/semmle/code/cpp/Declaration.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/cpp/ql/src/semmle/code/cpp/Declaration.qll b/cpp/ql/src/semmle/code/cpp/Declaration.qll index 1d5603fe4f4..31774170b6c 100644 --- a/cpp/ql/src/semmle/code/cpp/Declaration.qll +++ b/cpp/ql/src/semmle/code/cpp/Declaration.qll @@ -161,6 +161,7 @@ abstract class Declaration extends Locatable, @declaration { /** Holds if the declaration has a definition. */ predicate hasDefinition() { exists(this.getDefinition()) } + /** DEPRECATED: Use `hasDefinition` instead. */ predicate isDefined() { hasDefinition() } /** Gets the preferred location of this declaration, if any. */ From b5c0a0f77ddc6d45dd8854b5a0a5ab41247a0b94 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Tue, 14 Apr 2020 10:53:43 -0700 Subject: [PATCH 0137/1298] C++: remove all uses of Declaration::isDefined --- cpp/ql/src/JPL_C/LOC-3/Rule 17/BasicIntTypes.ql | 2 +- .../Security/CWE/CWE-457/InitializationFunctions.qll | 12 ++++++------ cpp/ql/src/semmle/code/cpp/Declaration.qll | 2 +- cpp/ql/src/semmle/code/cpp/UserType.qll | 2 +- .../code/cpp/security/FunctionWithWrappers.qll | 2 +- .../templates/prototype_bodies/isdef_hasblock.ql | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cpp/ql/src/JPL_C/LOC-3/Rule 17/BasicIntTypes.ql b/cpp/ql/src/JPL_C/LOC-3/Rule 17/BasicIntTypes.ql index 72852f0b86c..965bb8440b0 100644 --- a/cpp/ql/src/JPL_C/LOC-3/Rule 17/BasicIntTypes.ql +++ b/cpp/ql/src/JPL_C/LOC-3/Rule 17/BasicIntTypes.ql @@ -30,7 +30,7 @@ predicate allowedTypedefs(TypedefType t) { * Gets a type which appears literally in the declaration of `d`. */ Type getAnImmediateUsedType(Declaration d) { - d.isDefined() and + d.hasDefinition() and ( result = d.(Function).getType() or result = d.(Variable).getType() diff --git a/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll b/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll index a10e3df0bdd..c5285fdac57 100644 --- a/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll +++ b/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll @@ -198,12 +198,12 @@ class InitializationFunction extends Function { ) or // If we have no definition, we look at SAL annotations - not this.isDefined() and + not this.hasDefinition() and this.getParameter(i).(SALParameter).isOut() and evidence = SuggestiveSALAnnotation() or // We have some external information that this function conditionally initializes - not this.isDefined() and + not this.hasDefinition() and any(ValidatedExternalCondInitFunction vc).isExternallyVerified(this, i) and evidence = ExternalEvidence() } @@ -406,7 +406,7 @@ class ConditionalInitializationFunction extends InitializationFunction { * Explicitly ignore pure virtual functions. */ - this.isDefined() and + this.hasDefinition() and this.paramNotReassignedAt(this, i, c) and not this instanceof PureVirtualFunction ) @@ -616,11 +616,11 @@ private predicate functionSignature(Function f, string qualifiedName, string typ * are never statically linked together. */ private Function getAPossibleDefinition(Function undefinedFunction) { - not undefinedFunction.isDefined() and + not undefinedFunction.hasDefinition() and exists(string qn, string typeSig | functionSignature(undefinedFunction, qn, typeSig) and functionSignature(result, qn, typeSig) ) and - result.isDefined() + result.hasDefinition() } /** @@ -631,7 +631,7 @@ private Function getAPossibleDefinition(Function undefinedFunction) { */ private Function getTarget1(Call c) { result = VirtualDispatch::getAViableTarget(c) and - result.isDefined() + result.hasDefinition() } /** diff --git a/cpp/ql/src/semmle/code/cpp/Declaration.qll b/cpp/ql/src/semmle/code/cpp/Declaration.qll index 31774170b6c..a0eaa7fa1d0 100644 --- a/cpp/ql/src/semmle/code/cpp/Declaration.qll +++ b/cpp/ql/src/semmle/code/cpp/Declaration.qll @@ -304,7 +304,7 @@ abstract class DeclarationEntry extends Locatable { * available), or the name declared by this entry otherwise. */ string getCanonicalName() { - if getDeclaration().isDefined() + if getDeclaration().hasDefinition() then result = getDeclaration().getDefinition().getName() else result = getName() } diff --git a/cpp/ql/src/semmle/code/cpp/UserType.qll b/cpp/ql/src/semmle/code/cpp/UserType.qll index cbb7f39adbd..4484cde84de 100644 --- a/cpp/ql/src/semmle/code/cpp/UserType.qll +++ b/cpp/ql/src/semmle/code/cpp/UserType.qll @@ -38,7 +38,7 @@ class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @ override Specifier getASpecifier() { result = Type.super.getASpecifier() } override Location getLocation() { - if isDefined() + if hasDefinition() then result = this.getDefinitionLocation() else result = this.getADeclarationLocation() } diff --git a/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll b/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll index 8047bc384b2..23dda0ddb1e 100644 --- a/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll +++ b/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll @@ -19,7 +19,7 @@ private predicate wrapperFunctionStep( ) { not target.isVirtual() and not source.isVirtual() and - source.isDefined() and + source.hasDefinition() and exists(Call call, Expr arg, Parameter sourceParam | // there is a 'call' to 'target' with argument 'arg' at index 'targetParamIndex' target = resolveCall(call) and diff --git a/cpp/ql/test/library-tests/templates/prototype_bodies/isdef_hasblock.ql b/cpp/ql/test/library-tests/templates/prototype_bodies/isdef_hasblock.ql index c9cccbf24ae..be844bcf185 100644 --- a/cpp/ql/test/library-tests/templates/prototype_bodies/isdef_hasblock.ql +++ b/cpp/ql/test/library-tests/templates/prototype_bodies/isdef_hasblock.ql @@ -3,6 +3,6 @@ import cpp // It should be the case that "f.isDefined()" is equivalent to "exists(f.getBlock())". from Function f, string isdef, string hasblock where - (if f.isDefined() then isdef = "defined" else isdef = "not defined") and + (if f.hasDefinition() then isdef = "defined" else isdef = "not defined") and (if exists(f.getBlock()) then hasblock = "has block" else hasblock = "no block") select f.getName(), isdef, hasblock From 812087968f4ece49672227eba19a9611435a3ebf Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Tue, 14 Apr 2020 14:17:20 -0400 Subject: [PATCH 0138/1298] C++: Fix test output Mostly noise, but a couple of the missing operand errors are actual fixes. --- .../syntax-zoo/aliased_ssa_sanity.expected | 345 +++++++++--------- .../dataflow-ir-consistency.expected | 6 - .../syntax-zoo/raw_sanity.expected | 345 +++++++++--------- .../syntax-zoo/unaliased_ssa_sanity.expected | 345 +++++++++--------- 4 files changed, 505 insertions(+), 536 deletions(-) diff --git a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected index 362983363cc..7658b7f83f5 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected @@ -30,7 +30,6 @@ missingOperand unexpectedOperand duplicateOperand missingPhiOperand -| cpp11.cpp:141:7:141:7 | Phi: g | cpp11.cpp:161:16:161:16 | NoOp: label ...: | missingOperandType duplicateChiOperand sideEffectWithoutPrimary @@ -83,50 +82,48 @@ ambiguousSuccessors | assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | | assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | | assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | | conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | | conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | | conditional_destructors.cpp:38:6:38:7 | UnmodeledDefinition: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | @@ -213,50 +210,48 @@ ambiguousSuccessors | dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | | dostmt.c:25:6:25:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | | dostmt.c:25:6:25:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | | fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | | fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | | fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | @@ -361,50 +356,48 @@ ambiguousSuccessors | no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | | no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | | no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | | nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | | nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | | parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | @@ -463,50 +456,48 @@ ambiguousSuccessors | stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | | stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | | stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | | whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | | whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | | whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | diff --git a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected index b569b63cb61..f3e74c759b6 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected @@ -1,11 +1,5 @@ uniqueEnclosingCallable uniqueTypeBound -| break_labels.c:13:5:13:18 | VariableAddress | Node should have one type bound but has 2. | -| break_labels.c:13:12:13:17 | Store | Node should have one type bound but has 2. | -| enum.c:6:2:6:10 | VariableAddress | Node should have one type bound but has 2. | -| enum.c:6:9:6:9 | Store | Node should have one type bound but has 2. | -| parameterinitializer.cpp:4:5:4:13 | VariableAddress | Node should have one type bound but has 2. | -| parameterinitializer.cpp:4:12:4:12 | Store | Node should have one type bound but has 2. | uniqueTypeRepr uniqueNodeLocation | aggregateinitializer.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | diff --git a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected index cd5366a0c73..39d1fd19465 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected @@ -60,6 +60,7 @@ instructionWithoutSuccessor | condition_decls.cpp:48:52:48:53 | IndirectMayWriteSideEffect: call to BoxedInt | | cpp17.cpp:15:5:15:45 | InitializeDynamicAllocation: new | | cpp17.cpp:15:11:15:21 | Convert: (void *)... | +| enum.c:6:9:6:9 | Constant: (int)... | | file://:0:0:0:0 | CompareNE: (bool)... | | file://:0:0:0:0 | CompareNE: (bool)... | | file://:0:0:0:0 | CompareNE: (bool)... | @@ -140,50 +141,48 @@ ambiguousSuccessors | assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | | assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | | assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | | conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | | conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | | conditional_destructors.cpp:38:6:38:7 | UnmodeledDefinition: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | @@ -270,50 +269,48 @@ ambiguousSuccessors | dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | | dostmt.c:25:6:25:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | | dostmt.c:25:6:25:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | | fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | | fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | | fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | @@ -418,50 +415,48 @@ ambiguousSuccessors | no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | | no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | | no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | | nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | | nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | | parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | @@ -520,50 +515,48 @@ ambiguousSuccessors | stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | | stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | | stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | | whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | | whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | | whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | diff --git a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected index 82b5f5ccef0..98d70df2f53 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected @@ -30,7 +30,6 @@ missingOperand unexpectedOperand duplicateOperand missingPhiOperand -| cpp11.cpp:141:7:141:7 | Phi: g | cpp11.cpp:161:16:161:16 | NoOp: label ...: | | range_analysis.c:373:3:373:47 | Phi: return ... | range_analysis.c:371:37:371:39 | Constant: 500 | | range_analysis.c:373:3:373:47 | Phi: return ... | range_analysis.c:371:37:371:39 | Constant: 500 | | range_analysis.c:373:3:373:47 | Phi: return ... | range_analysis.c:371:37:371:39 | Constant: 500 | @@ -92,50 +91,48 @@ ambiguousSuccessors | assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | | assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | | assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | | conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | | conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | | conditional_destructors.cpp:38:6:38:7 | UnmodeledDefinition: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | @@ -222,50 +219,48 @@ ambiguousSuccessors | dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | | dostmt.c:25:6:25:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | | dostmt.c:25:6:25:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | | fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | | fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | | fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | @@ -370,50 +365,48 @@ ambiguousSuccessors | no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | | no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | | no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | | nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | | nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | | parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | @@ -472,50 +465,48 @@ ambiguousSuccessors | stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | | stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | | stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | | whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | | whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | | whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | From 279467654ecabf20a92e8e89d45a2ad9d56133cb Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Tue, 14 Apr 2020 14:17:56 -0400 Subject: [PATCH 0139/1298] C++: Make test functions return `void` --- .../GlobalValueNumbering/ir_gvn.expected | 116 ++++++++---------- .../GlobalValueNumbering/test.cpp | 8 +- 2 files changed, 58 insertions(+), 66 deletions(-) diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected index a492fb47d41..e585bd806eb 100644 --- a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected +++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected @@ -1,80 +1,78 @@ test.cpp: -# 1| int test00(int, int) +# 1| void test00(int, int) # 1| Block 0 -# 1| v1_1(void) = EnterFunction : -# 1| m1_2(unknown) = AliasedDefinition : +# 1| v1_1(void) = EnterFunction : +# 1| m1_2(unknown) = AliasedDefinition : # 1| valnum = unique -# 1| m1_3(unknown) = InitializeNonLocal : +# 1| m1_3(unknown) = InitializeNonLocal : # 1| valnum = unique -# 1| m1_4(unknown) = Chi : total:m1_2, partial:m1_3 +# 1| m1_4(unknown) = Chi : total:m1_2, partial:m1_3 # 1| valnum = unique -# 1| mu1_5(unknown) = UnmodeledDefinition : +# 1| mu1_5(unknown) = UnmodeledDefinition : # 1| valnum = unique -# 1| r1_6(glval) = VariableAddress[p0] : +# 1| r1_6(glval) = VariableAddress[p0] : # 1| valnum = r1_6, r5_1, r6_1 -# 1| m1_7(int) = InitializeParameter[p0] : &:r1_6 +# 1| m1_7(int) = InitializeParameter[p0] : &:r1_6 # 1| valnum = m1_7, r5_2, r6_2 -# 1| r1_8(glval) = VariableAddress[p1] : +# 1| r1_8(glval) = VariableAddress[p1] : # 1| valnum = r1_8, r5_3, r6_3 -# 1| m1_9(int) = InitializeParameter[p1] : &:r1_8 +# 1| m1_9(int) = InitializeParameter[p1] : &:r1_8 # 1| valnum = m1_9, r5_4, r6_4 -# 2| r2_1(glval) = VariableAddress[x] : +# 2| r2_1(glval) = VariableAddress[x] : # 2| valnum = r2_1, r5_6, r6_6, r7_1 -# 2| m2_2(int) = Uninitialized[x] : &:r2_1 +# 2| m2_2(int) = Uninitialized[x] : &:r2_1 # 2| valnum = unique -# 2| r2_3(glval) = VariableAddress[y] : +# 2| r2_3(glval) = VariableAddress[y] : # 2| valnum = r2_3, r7_3 -# 2| m2_4(int) = Uninitialized[y] : &:r2_3 +# 2| m2_4(int) = Uninitialized[y] : &:r2_3 # 2| valnum = unique -# 3| r3_1(glval) = VariableAddress[b] : +# 3| r3_1(glval) = VariableAddress[b] : # 3| valnum = unique -# 3| m3_2(unsigned char) = Uninitialized[b] : &:r3_1 +# 3| m3_2(unsigned char) = Uninitialized[b] : &:r3_1 # 3| valnum = unique -# 5| r5_1(glval) = VariableAddress[p0] : +# 5| r5_1(glval) = VariableAddress[p0] : # 5| valnum = r1_6, r5_1, r6_1 -# 5| r5_2(int) = Load : &:r5_1, m1_7 +# 5| r5_2(int) = Load : &:r5_1, m1_7 # 5| valnum = m1_7, r5_2, r6_2 -# 5| r5_3(glval) = VariableAddress[p1] : +# 5| r5_3(glval) = VariableAddress[p1] : # 5| valnum = r1_8, r5_3, r6_3 -# 5| r5_4(int) = Load : &:r5_3, m1_9 +# 5| r5_4(int) = Load : &:r5_3, m1_9 # 5| valnum = m1_9, r5_4, r6_4 -# 5| r5_5(int) = Add : r5_2, r5_4 +# 5| r5_5(int) = Add : r5_2, r5_4 # 5| valnum = m5_7, m6_7, m7_4, r5_5, r6_5, r7_2 -# 5| r5_6(glval) = VariableAddress[x] : +# 5| r5_6(glval) = VariableAddress[x] : # 5| valnum = r2_1, r5_6, r6_6, r7_1 -# 5| m5_7(int) = Store : &:r5_6, r5_5 +# 5| m5_7(int) = Store : &:r5_6, r5_5 # 5| valnum = m5_7, m6_7, m7_4, r5_5, r6_5, r7_2 -# 6| r6_1(glval) = VariableAddress[p0] : +# 6| r6_1(glval) = VariableAddress[p0] : # 6| valnum = r1_6, r5_1, r6_1 -# 6| r6_2(int) = Load : &:r6_1, m1_7 +# 6| r6_2(int) = Load : &:r6_1, m1_7 # 6| valnum = m1_7, r5_2, r6_2 -# 6| r6_3(glval) = VariableAddress[p1] : +# 6| r6_3(glval) = VariableAddress[p1] : # 6| valnum = r1_8, r5_3, r6_3 -# 6| r6_4(int) = Load : &:r6_3, m1_9 +# 6| r6_4(int) = Load : &:r6_3, m1_9 # 6| valnum = m1_9, r5_4, r6_4 -# 6| r6_5(int) = Add : r6_2, r6_4 +# 6| r6_5(int) = Add : r6_2, r6_4 # 6| valnum = m5_7, m6_7, m7_4, r5_5, r6_5, r7_2 -# 6| r6_6(glval) = VariableAddress[x] : +# 6| r6_6(glval) = VariableAddress[x] : # 6| valnum = r2_1, r5_6, r6_6, r7_1 -# 6| m6_7(int) = Store : &:r6_6, r6_5 +# 6| m6_7(int) = Store : &:r6_6, r6_5 # 6| valnum = m5_7, m6_7, m7_4, r5_5, r6_5, r7_2 -# 7| r7_1(glval) = VariableAddress[x] : +# 7| r7_1(glval) = VariableAddress[x] : # 7| valnum = r2_1, r5_6, r6_6, r7_1 -# 7| r7_2(int) = Load : &:r7_1, m6_7 +# 7| r7_2(int) = Load : &:r7_1, m6_7 # 7| valnum = m5_7, m6_7, m7_4, r5_5, r6_5, r7_2 -# 7| r7_3(glval) = VariableAddress[y] : +# 7| r7_3(glval) = VariableAddress[y] : # 7| valnum = r2_3, r7_3 -# 7| m7_4(int) = Store : &:r7_3, r7_2 +# 7| m7_4(int) = Store : &:r7_3, r7_2 # 7| valnum = m5_7, m6_7, m7_4, r5_5, r6_5, r7_2 -# 8| v8_1(void) = NoOp : -# 1| r1_10(glval) = VariableAddress[#return] : -# 1| valnum = unique -# 1| v1_11(void) = ReturnValue : &:r1_10 -# 1| v1_12(void) = UnmodeledUse : mu* -# 1| v1_13(void) = AliasedUse : m1_3 -# 1| v1_14(void) = ExitFunction : +# 8| v8_1(void) = NoOp : +# 1| v1_10(void) = ReturnVoid : +# 1| v1_11(void) = UnmodeledUse : mu* +# 1| v1_12(void) = AliasedUse : m1_3 +# 1| v1_13(void) = ExitFunction : -# 12| int test01(int, int) +# 12| void test01(int, int) # 12| Block 0 # 12| v12_1(void) = EnterFunction : # 12| m12_2(unknown) = AliasedDefinition : @@ -154,14 +152,12 @@ test.cpp: # 18| m18_4(int) = Store : &:r18_3, r18_2 # 18| valnum = m16_10, m17_10, m18_4, r16_8, r17_8, r18_2 # 19| v19_1(void) = NoOp : -# 12| r12_10(glval) = VariableAddress[#return] : -# 12| valnum = unique -# 12| v12_11(void) = ReturnValue : &:r12_10 -# 12| v12_12(void) = UnmodeledUse : mu* -# 12| v12_13(void) = AliasedUse : m12_3 -# 12| v12_14(void) = ExitFunction : +# 12| v12_10(void) = ReturnVoid : +# 12| v12_11(void) = UnmodeledUse : mu* +# 12| v12_12(void) = AliasedUse : m12_3 +# 12| v12_13(void) = ExitFunction : -# 25| int test02(int, int) +# 25| void test02(int, int) # 25| Block 0 # 25| v25_1(void) = EnterFunction : # 25| m25_2(unknown) = AliasedDefinition : @@ -248,14 +244,12 @@ test.cpp: # 32| m32_4(int) = Store : &:r32_3, r32_2 # 32| valnum = m31_10, m32_4, r31_8, r32_2 # 33| v33_1(void) = NoOp : -# 25| r25_10(glval) = VariableAddress[#return] : -# 25| valnum = unique -# 25| v25_11(void) = ReturnValue : &:r25_10 -# 25| v25_12(void) = UnmodeledUse : mu* -# 25| v25_13(void) = AliasedUse : ~m30_4 -# 25| v25_14(void) = ExitFunction : +# 25| v25_10(void) = ReturnVoid : +# 25| v25_11(void) = UnmodeledUse : mu* +# 25| v25_12(void) = AliasedUse : ~m30_4 +# 25| v25_13(void) = ExitFunction : -# 39| int test03(int, int, int*) +# 39| void test03(int, int, int*) # 39| Block 0 # 39| v39_1(void) = EnterFunction : # 39| m39_2(unknown) = AliasedDefinition : @@ -356,12 +350,10 @@ test.cpp: # 46| valnum = m43_10, m45_10, m46_4, r43_8, r45_8, r46_2 # 47| v47_1(void) = NoOp : # 39| v39_14(void) = ReturnIndirection : &:r39_12, m44_6 -# 39| r39_15(glval) = VariableAddress[#return] : -# 39| valnum = unique -# 39| v39_16(void) = ReturnValue : &:r39_15 -# 39| v39_17(void) = UnmodeledUse : mu* -# 39| v39_18(void) = AliasedUse : m39_3 -# 39| v39_19(void) = ExitFunction : +# 39| v39_15(void) = ReturnVoid : +# 39| v39_16(void) = UnmodeledUse : mu* +# 39| v39_17(void) = AliasedUse : m39_3 +# 39| v39_18(void) = ExitFunction : # 49| unsigned int my_strspn(char const*, char const*) # 49| Block 0 diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/test.cpp b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/test.cpp index 3e878ac2356..dfef91006e3 100644 --- a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/test.cpp +++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/test.cpp @@ -1,4 +1,4 @@ -int test00(int p0, int p1) { +void test00(int p0, int p1) { int x, y; unsigned char b; @@ -9,7 +9,7 @@ int test00(int p0, int p1) { int global01 = 1; -int test01(int p0, int p1) { +void test01(int p0, int p1) { int x, y; unsigned char b; @@ -22,7 +22,7 @@ int global02 = 2; void change_global02(); // Just a declaration -int test02(int p0, int p1) { +void test02(int p0, int p1) { int x, y; unsigned char b; @@ -36,7 +36,7 @@ int global03 = 3; void change_global03(); // Just a declaration -int test03(int p0, int p1, int* p2) { +void test03(int p0, int p1, int* p2) { int x, y; unsigned char b; From 1107e7c6a6f9b7e529da21378e23183c138736a1 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 14 Apr 2020 19:45:09 +0100 Subject: [PATCH 0140/1298] JS: Rename other uses of getURL --- javascript/ql/src/semmle/javascript/NPM.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/NPM.qll b/javascript/ql/src/semmle/javascript/NPM.qll index 1038b04b6c2..24d3072fae1 100644 --- a/javascript/ql/src/semmle/javascript/NPM.qll +++ b/javascript/ql/src/semmle/javascript/NPM.qll @@ -233,7 +233,7 @@ class ContributorInfo extends JSONValue { } /** Gets the contributor's homepage URL. */ - string getURL() { + string getUrl() { result = this.(JSONObject).getPropStringValue("url") or result = parseInfo(3) } @@ -249,7 +249,7 @@ class RepositoryInfo extends JSONObject { string getType() { result = getPropStringValue("type") } /** Gets the repository URL. */ - string getURL() { result = getPropStringValue("url") } + string getUrl() { result = getPropStringValue("url") } } /** From a2fbe9e9dad54118a86b22c2f93b7060f91bb794 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 14 Apr 2020 17:22:03 +0200 Subject: [PATCH 0141/1298] C++: Add QLDoc to public predicates in Negativity --- cpp/ql/src/Critical/Negativity.qll | 61 ++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/cpp/ql/src/Critical/Negativity.qll b/cpp/ql/src/Critical/Negativity.qll index 161fe234967..2eb6906573f 100644 --- a/cpp/ql/src/Critical/Negativity.qll +++ b/cpp/ql/src/Critical/Negativity.qll @@ -1,10 +1,19 @@ import cpp +/** + * Holds if `val` is an access to the variable `v`, or if `val` + * is an assignment with an access to `v` on the left-hand side. + */ predicate valueOfVar(Variable v, Expr val) { val = v.getAnAccess() or val.(AssignExpr).getLValue() = v.getAnAccess() } +/** + * Holds if either: + * - `cond` is an (in)equality expression that compares the variable `v` to the value `-1`, or + * - `cond` is a relational expression that compares the variable `v` to a constant. + */ predicate boundsCheckExpr(Variable v, Expr cond) { exists(EQExpr eq | cond = eq and @@ -43,6 +52,18 @@ predicate boundsCheckExpr(Variable v, Expr cond) { ) } +/** + * Holds if `node` is an expression in a conditional statement and `succ` is an + * immediate successor of `node` that may be reached after evaluating `node`. + * For example, given + * ``` + * if (a < 10 && b) func1(); + * else func2(); + * ``` + * this predicate holds when either: + * - `node` is `a < 10` and `succ` is `func2()` or `b`, or + * - `node` is `b` and `succ` is `func1()` or `func2()` + */ predicate conditionalSuccessor(ControlFlowNode node, ControlFlowNode succ) { if node.isCondition() then succ = node.getATrueSuccessor() or succ = node.getAFalseSuccessor() @@ -52,6 +73,12 @@ predicate conditionalSuccessor(ControlFlowNode node, ControlFlowNode succ) { ) } +/** + * Holds if the current value of the variable `v` at control-flow + * node `n` has been used either in: + * - an (in)equality comparison with the value `-1`, or + * - a relational comparison that compares `v` to a constant. + */ predicate boundsChecked(Variable v, ControlFlowNode node) { exists(Expr test | boundsCheckExpr(v, test) and @@ -63,6 +90,14 @@ predicate boundsChecked(Variable v, ControlFlowNode node) { ) } +/** + * Holds if `cond` compares `v` to some common error values. Specifically, this + * predicate holds when: + * - `cond` checks that `v` is equal to `-1`, or + * - `cond` checks that `v` is less than `0`, or + * - `cond` checks that `v` is less than or equal to `-1`, or + * - `cond` checks that `v` is not some common success value (see `successCondition`). + */ predicate errorCondition(Variable v, Expr cond) { exists(EQExpr eq | cond = eq and @@ -88,6 +123,14 @@ predicate errorCondition(Variable v, Expr cond) { ) } +/** + * Holds if `cond` compares `v` to some common success values. Specifically, this + * predicate holds when: + * - `cond` checks that `v` is not equal to `-1`, or + * - `cond` checks that `v` is greater than or equal than `0`, or + * - `cond` checks that `v` is greater than `-1`, or + * - `cond` checks that `v` is not some common success value (see `errorCondition`). + */ predicate successCondition(Variable v, Expr cond) { exists(NEExpr ne | cond = ne and @@ -113,6 +156,11 @@ predicate successCondition(Variable v, Expr cond) { ) } +/** + * Holds if there exists a comparison operation that checks whether `v` + * represents some common *error* values, and `n` may be reached + * immediately following the comparison operation. + */ predicate errorSuccessor(Variable v, ControlFlowNode n) { exists(Expr cond | errorCondition(v, cond) and n = cond.getATrueSuccessor() @@ -121,6 +169,11 @@ predicate errorSuccessor(Variable v, ControlFlowNode n) { ) } +/** + * Holds if there exists a comparison operation that checks whether `v` + * represents some common *success* values, and `n` may be reached + * immediately following the comparison operation. + */ predicate successSuccessor(Variable v, ControlFlowNode n) { exists(Expr cond | successCondition(v, cond) and n = cond.getATrueSuccessor() @@ -129,6 +182,10 @@ predicate successSuccessor(Variable v, ControlFlowNode n) { ) } +/** + * Holds if the current value of the variable `v` at control-flow node + * `n` may have been checked against a common set of *error* values. + */ predicate checkedError(Variable v, ControlFlowNode n) { errorSuccessor(v, n) or @@ -139,6 +196,10 @@ predicate checkedError(Variable v, ControlFlowNode n) { ) } +/** + * Holds if the current value of the variable `v` at control-flow node + * `n` may have been checked against a common set of *error* values. + */ predicate checkedSuccess(Variable v, ControlFlowNode n) { successSuccessor(v, n) or From 679259944fb6e411a433a02ea2285e8f273a6487 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 15 Apr 2020 10:27:32 +0100 Subject: [PATCH 0142/1298] JS: Address review comments --- .../semmle/javascript/frameworks/SocketIO.qll | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/SocketIO.qll b/javascript/ql/src/semmle/javascript/frameworks/SocketIO.qll index 490f44fc758..7288b624bce 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/SocketIO.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/SocketIO.qll @@ -85,8 +85,6 @@ module SocketIO { /** * DEPRECATED. Always returns `this` as a `ServerObject` now represents the origin of a server. - * - * Instead of `getOrigin()` to get a server origin from a reference, use `ServerObject.ref()` to get references to a given server. */ deprecated DataFlow::SourceNode getOrigin() { result = this } } @@ -285,9 +283,8 @@ module SocketIO { SendNode getASender() { result.getAReceiver() = this } /** Gets the acknowledgment callback, if any. */ - DataFlow::FunctionNode getAck() { - result = getListener().getLastParameter() and - exists(result.getAnInvocation()) + DataFlow::SourceNode getAck() { + result.(ReceiveCallback).getReceiveNode() = this } /** DEPRECATED. Use `getChannel()` instead. */ @@ -311,6 +308,9 @@ module SocketIO { override SocketIOClient::SendCallback getAReceiver() { result.getSendNode().getAReceiver() = rcv } + + /** Gets the API call to which this is a callback. */ + ReceiveNode getReceiveNode() { result = rcv } } /** @@ -575,7 +575,7 @@ module SocketIOClient { DataFlow::SourceNode getAReceivedItem() { result = getReceivedItem(_) } /** Gets the acknowledgment callback, if any. */ - DataFlow::FunctionNode getAck() { + DataFlow::SourceNode getAck() { result = getListener().getLastParameter() and exists(result.getAnInvocation()) } @@ -588,11 +588,11 @@ module SocketIOClient { } /** An acknowledgment callback from a receive node. */ - class RecieveCallback extends EventDispatch::Range, DataFlow::SourceNode { + class ReceiveCallback extends EventDispatch::Range, DataFlow::SourceNode { override SocketObject emitter; ReceiveNode rcv; - RecieveCallback() { + ReceiveCallback() { this = rcv.getListener().getLastParameter() and exists(this.getAnInvocation()) and emitter = rcv.getEmitter() From f02feac33a36c27363f748f5bc4e0e32ac2124b3 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 15 Apr 2020 11:34:19 +0200 Subject: [PATCH 0143/1298] C++: Add flow from #3220 --- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 3 ++ .../dataflow/fields/ir-flow.expected | 41 +++++++++++++++++++ 2 files changed, 44 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 cfe1196d5e9..c5c994a8509 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 @@ -430,6 +430,9 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction // for now. iTo.getAnOperand().(ChiTotalOperand).getDef() = iFrom or + iTo.getAnOperand().(ChiPartialOperand).getDef() = iFrom.(WriteSideEffectInstruction) and + not iTo.isResultConflated() + or exists(ChiInstruction chi | iFrom = chi | not chi.isResultConflated() and iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = chi 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 15a6d699adb..7a6432e29f3 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected @@ -1,4 +1,21 @@ edges +| A.cpp:142:7:142:20 | Chi [c] | A.cpp:151:18:151:18 | D output argument [c] | +| A.cpp:142:7:142:20 | Store | A.cpp:142:7:142:20 | Chi [c] | +| A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | Store | +| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | +| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | +| A.cpp:151:18:151:18 | D output argument [c] | A.cpp:151:18:151:18 | Chi [c] | +| A.cpp:154:13:154:13 | c | A.cpp:154:10:154:13 | (void *)... | +| aliasing.cpp:9:3:9:22 | Chi [m1] | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | +| aliasing.cpp:9:3:9:22 | Store | aliasing.cpp:9:3:9:22 | Chi [m1] | +| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | Store | +| aliasing.cpp:13:3:13:21 | Chi [m1] | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | +| aliasing.cpp:13:3:13:21 | Store | aliasing.cpp:13:3:13:21 | Chi [m1] | +| aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:3:13:21 | Store | +| aliasing.cpp:25:17:25:19 | Chi [m1] | aliasing.cpp:29:11:29:12 | m1 | +| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | aliasing.cpp:25:17:25:19 | Chi [m1] | +| aliasing.cpp:26:19:26:20 | Chi [m1] | aliasing.cpp:30:11:30:12 | m1 | +| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | aliasing.cpp:26:19:26:20 | Chi [m1] | | aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | | aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | | aliasing.cpp:60:3:60:22 | Chi [m1] | aliasing.cpp:61:13:61:14 | Store [m1] | @@ -11,6 +28,26 @@ edges | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | nodes +| A.cpp:142:7:142:20 | Chi [c] | semmle.label | Chi [c] | +| A.cpp:142:7:142:20 | Store | semmle.label | Store | +| A.cpp:142:14:142:20 | new | semmle.label | new | +| A.cpp:151:18:151:18 | Chi [c] | semmle.label | Chi [c] | +| A.cpp:151:18:151:18 | D output argument [c] | semmle.label | D output argument [c] | +| A.cpp:154:10:154:13 | (void *)... | semmle.label | (void *)... | +| A.cpp:154:13:154:13 | c | semmle.label | c | +| A.cpp:154:13:154:13 | c | semmle.label | c | +| aliasing.cpp:9:3:9:22 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:9:3:9:22 | Store | semmle.label | Store | +| aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:13:3:13:21 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:13:3:13:21 | Store | semmle.label | Store | +| aliasing.cpp:13:10:13:19 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:25:17:25:19 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | semmle.label | pointerSetter output argument [m1] | +| aliasing.cpp:26:19:26:20 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | semmle.label | referenceSetter output argument [m1] | +| aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 | +| aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 | | aliasing.cpp:37:13:37:22 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:38:11:38:12 | m1 | semmle.label | m1 | | aliasing.cpp:42:11:42:20 | call to user_input | semmle.label | call to user_input | @@ -31,6 +68,10 @@ nodes | struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input | | struct_init.c:31:23:31:23 | a | semmle.label | a | #select +| A.cpp:154:10:154:13 | (void *)... | A.cpp:142:14:142:20 | new | A.cpp:154:10:154:13 | (void *)... | (void *)... flows from $@ | A.cpp:142:14:142:20 | new | new | +| A.cpp:154:13:154:13 | c | A.cpp:142:14:142:20 | new | A.cpp:154:13:154:13 | c | c flows from $@ | A.cpp:142:14:142:20 | new | new | +| aliasing.cpp:29:11:29:12 | m1 | aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:29:11:29:12 | m1 | m1 flows from $@ | aliasing.cpp:9:11:9:20 | call to user_input | call to user_input | +| aliasing.cpp:30:11:30:12 | m1 | aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:30:11:30:12 | m1 | m1 flows from $@ | aliasing.cpp:13:10:13:19 | call to user_input | call to user_input | | aliasing.cpp:38:11:38:12 | m1 | aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | m1 flows from $@ | aliasing.cpp:37:13:37:22 | call to user_input | call to user_input | | aliasing.cpp:43:13:43:14 | m1 | aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | m1 flows from $@ | aliasing.cpp:42:11:42:20 | call to user_input | call to user_input | | aliasing.cpp:62:14:62:15 | m1 | aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:62:14:62:15 | m1 | m1 flows from $@ | aliasing.cpp:60:11:60:20 | call to user_input | call to user_input | From b8acd702d6bc09afabd15d4a425be4cb47671f8f Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 14 Apr 2020 13:06:39 +0100 Subject: [PATCH 0144/1298] C++: Rename the test for consistency. --- .../ComparisonWithWiderType.expected | 0 .../ComparisonWithWiderType.qlref | 0 .../CWE-190/semmle/{wider_type => ComparisonWithWiderType}/test.c | 0 .../semmle/{wider_type => ComparisonWithWiderType}/test2.c | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/{wider_type => ComparisonWithWiderType}/ComparisonWithWiderType.expected (100%) rename cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/{wider_type => ComparisonWithWiderType}/ComparisonWithWiderType.qlref (100%) rename cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/{wider_type => ComparisonWithWiderType}/test.c (100%) rename cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/{wider_type => ComparisonWithWiderType}/test2.c (100%) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/wider_type/ComparisonWithWiderType.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/ComparisonWithWiderType.expected similarity index 100% rename from cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/wider_type/ComparisonWithWiderType.expected rename to cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/ComparisonWithWiderType.expected diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/wider_type/ComparisonWithWiderType.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/ComparisonWithWiderType.qlref similarity index 100% rename from cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/wider_type/ComparisonWithWiderType.qlref rename to cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/ComparisonWithWiderType.qlref diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/wider_type/test.c b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test.c similarity index 100% rename from cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/wider_type/test.c rename to cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test.c diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/wider_type/test2.c b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test2.c similarity index 100% rename from cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/wider_type/test2.c rename to cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test2.c From 3d0ac53266fb4d650d8406588542cb53090e0fd3 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 15 Apr 2020 14:01:49 +0200 Subject: [PATCH 0145/1298] Apply suggestions from code review Co-Authored-By: Jonas Jensen --- cpp/ql/src/Critical/Negativity.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/Critical/Negativity.qll b/cpp/ql/src/Critical/Negativity.qll index 2eb6906573f..e9c0a3d2410 100644 --- a/cpp/ql/src/Critical/Negativity.qll +++ b/cpp/ql/src/Critical/Negativity.qll @@ -129,7 +129,7 @@ predicate errorCondition(Variable v, Expr cond) { * - `cond` checks that `v` is not equal to `-1`, or * - `cond` checks that `v` is greater than or equal than `0`, or * - `cond` checks that `v` is greater than `-1`, or - * - `cond` checks that `v` is not some common success value (see `errorCondition`). + * - `cond` checks that `v` is not some common error value (see `errorCondition`). */ predicate successCondition(Variable v, Expr cond) { exists(NEExpr ne | @@ -198,7 +198,7 @@ predicate checkedError(Variable v, ControlFlowNode n) { /** * Holds if the current value of the variable `v` at control-flow node - * `n` may have been checked against a common set of *error* values. + * `n` may have been checked against a common set of *success* values. */ predicate checkedSuccess(Variable v, ControlFlowNode n) { successSuccessor(v, n) From 7e67dcca6f186a39313493e90d41862428473f0e Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Wed, 15 Apr 2020 15:41:23 +0200 Subject: [PATCH 0146/1298] C++: Tidy up 1.24 change notes - Merged the two notes for `cpp/uncontrolled-allocation-size` into one. - Added note about renaming of a query id. - Moved the use of IR in queries from the library section to the queries section, rephrasing the note in terms of query results/performance rather than library implementation. - Grouped, without text changes, the three notes about the `Allocation` library - Grouped all the notes about standard-library models, abbreviating them to eliminate the common text. - Removed the note about `strlen` (#2647) since that should no longer affect the results of queries or IR data flow after we started using unsound IR for data flow. --- change-notes/1.24/analysis-cpp.md | 36 +++++++++++++++++++------------ 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/change-notes/1.24/analysis-cpp.md b/change-notes/1.24/analysis-cpp.md index 8f8c3d5364a..78e86c29c31 100644 --- a/change-notes/1.24/analysis-cpp.md +++ b/change-notes/1.24/analysis-cpp.md @@ -24,11 +24,14 @@ The following changes in version 1.24 affect C/C++ analysis in all applications. | No space for zero terminator (`cpp/no-space-for-terminator`) | More correct results | String arguments to formatting functions are now (usually) expected to be null terminated strings. | | Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) | | This query is no longer run on LGTM. | | No space for zero terminator (`cpp/no-space-for-terminator`) | Fewer false positive results | This query has been modified to be more conservative when identifying which pointers point to null-terminated strings. This approach produces fewer, more accurate results. | -| Overflow in uncontrolled allocation size (`cpp/uncontrolled-allocation-size`) | Fewer false positive results | Cases where the tainted allocation size is range checked are now more reliably excluded. | -| Overflow in uncontrolled allocation size (`cpp/uncontrolled-allocation-size`) | Fewer false positive results | The query now produces fewer, more accurate results. | +| Overflow in uncontrolled allocation size (`cpp/uncontrolled-allocation-size`) | Fewer false positive results | The query now produces fewer, more accurate results. Cases where the tainted allocation size is range checked are more reliably excluded. | | Overloaded assignment does not return 'this' (`cpp/assignment-does-not-return-this`) | Fewer false positive results | This query no longer reports incorrect results in template classes. | | Unsafe array for days of the year (`cpp/leap-year/unsafe-array-for-days-of-the-year`) | | This query is no longer run on LGTM. | +| Boost\_asio TLS Settings Misconfiguration (`cpp/boost/tls-settings-misconfiguration`) | Query id change | Query id renamed from `cpp/boost/tls_settings_misconfiguration` (underscores to dashes) | | Unsigned comparison to zero (`cpp/unsigned-comparison-zero`) | More correct results | This query now also looks for comparisons of the form `0 <= x`. | +| Signed overflow check (`cpp/signed-overflow-check`), Pointer overflow check (`cpp/pointer-overflow-check`), Possibly wrong buffer size in string copy (`cpp/bad-strncpy-size`) | More correct results | A new library is used for determining which expressions have identical value, giving more precise results. There is a performance cost to this, and the LGTM suite will overall run slower than before. | +| All CWE-specific queries using taint tracking (`cpp/path-injection`, `cpp/cgi-xss`, `cpp/sql-injection`, `cpp/uncontrolled-process-operation`, `cpp/unbounded-write`, `cpp/tainted-format-string`, `cpp/tainted-format-string-through-global`, `cpp/uncontrolled-arithmetic`, `cpp/uncontrolled-allocation-size`, `cpp/user-controlled-bypass`, `cpp/cleartext-storage-buffer`, `cpp/tainted-permissions-check`) | More correct results | A new taint-tracking library is used, giving more precise results and offering _path explanations_ for results. There is a performance cost to this, and the LGTM suite will overall run slower than before. | + ## Changes to libraries @@ -36,8 +39,17 @@ The following changes in version 1.24 affect C/C++ analysis in all applications. - Track flow through functions that combine taint tracking with flow through fields. - Track flow through clone-like functions, that is, functions that read contents of a field from a parameter and stores the value in the field of a returned object. -* Created the `semmle.code.cpp.models.interfaces.Allocation` library to model allocation such as `new` expressions and calls to `malloc`. This in intended to replace the functionality in `semmle.code.cpp.commons.Alloc` with a more consistent and useful interface. -* Created the `semmle.code.cpp.models.interfaces.Deallocation` library to model deallocation such as `delete` expressions and calls to `free`. This in intended to replace the functionality in `semmle.code.cpp.commons.Alloc` with a more consistent and useful interface. +* Created the `semmle.code.cpp.models.interfaces.Allocation` library to model + allocation such as `new` expressions and calls to `malloc`. This in intended + to replace the functionality in `semmle.code.cpp.commons.Alloc` with a more + consistent and useful interface. + * The predicate `freeCall` in `semmle.code.cpp.commons.Alloc` has been + deprecated. The`Allocation` and `Deallocation` models in + `semmle.code.cpp.models.interfaces` should be used instead. + * Created the `semmle.code.cpp.models.interfaces.Deallocation` library to + model deallocation such as `delete` expressions and calls to `free`. This + in intended to replace the functionality in `semmle.code.cpp.commons.Alloc` + with a more consistent and useful interface. * The new class `StackVariable` should be used in place of `LocalScopeVariable` in most cases. The difference is that `StackVariable` does not include variables declared with `static` or `thread_local`. @@ -46,13 +58,9 @@ The following changes in version 1.24 affect C/C++ analysis in all applications. about the _name or scope_ of variables should remain unchanged. * The `LocalScopeVariableReachability` library is deprecated in favor of `StackVariableReachability`. The functionality is the same. -* The models library models `strlen` in more detail, and includes common variations such as `wcslen`. -* The models library models `gets` and similar functions. -* The models library now partially models `std::string`. -* The taint tracking library (`semmle.code.cpp.dataflow.TaintTracking`) has had - the following improvements: - * The library now models data flow through `strdup` and similar functions. - * The library now models data flow through formatting functions such as `sprintf`. -* The security pack taint tracking library (`semmle.code.cpp.security.TaintTracking`) uses a new intermediate representation. This provides a more precise analysis of pointers to stack variables and flow through parameters, improving the results of many security queries. -* The global value numbering library (`semmle.code.cpp.valuenumbering.GlobalValueNumbering`) uses a new intermediate representation to provide a more precise analysis of heap allocated memory and pointers to stack variables. -* `freeCall` in `semmle.code.cpp.commons.Alloc` has been deprecated. The`Allocation` and `Deallocation` models in `semmle.code.cpp.models.interfaces` should be used instead. +* Taint tracking and data flow now features better modeling of commonly-used + library functions: + * `gets` and similar functions, + * the most common operations on `std::string`, + * `strdup` and similar functions, and + * formatting functions such as `sprintf`. From b179a0bdc2424ef42565f7fa95482cf55edf5111 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 15 Apr 2020 16:59:07 +0200 Subject: [PATCH 0147/1298] Python: Add deprecated comment for FinalCustomPointsToFact --- python/ql/src/semmle/python/types/Extensions.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/types/Extensions.qll b/python/ql/src/semmle/python/types/Extensions.qll index 78ad15d7fbd..19e05875826 100644 --- a/python/ql/src/semmle/python/types/Extensions.qll +++ b/python/ql/src/semmle/python/types/Extensions.qll @@ -37,7 +37,7 @@ abstract deprecated class CustomPointsToFact extends @py_flow_node { abstract predicate pointsTo(Context context, Object value, ClassObject cls, ControlFlowNode origin); } -/* For backwards compatibility */ +/** DEPRECATED -- Use PointsToExtension instead */ deprecated class FinalCustomPointsToFact = CustomPointsToFact; abstract deprecated class CustomPointsToOriginFact extends CustomPointsToFact { From e8dc77d5080a1c5461a570e8fee0188800b56d7d Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 15 Apr 2020 14:06:16 +0200 Subject: [PATCH 0148/1298] add support for util.promisify with child_process calls --- .../semmle/javascript/frameworks/NodeJSLib.qll | 8 ++++++++ .../Security/CWE-078/CommandInjection.expected | 16 ++++++++++++++++ .../Security/CWE-078/child_process-test.js | 9 +++++++++ 3 files changed, 33 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll index 78393a1aabf..bf343b28603 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll @@ -594,6 +594,14 @@ module NodeJSLib { ChildProcessMethodCall() { this = DataFlow::moduleMember("child_process", methodName).getACall() + or + exists(DataFlow::CallNode promisify | + promisify = DataFlow::moduleMember("util", "promisify").getACall() + | + this = promisify.getACall() and + promisify.getArgument(0).getALocalSource() = + DataFlow::moduleMember("child_process", methodName) + ) } private DataFlow::Node getACommandArgument(boolean shell) { diff --git a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected index 589deda96c9..caffc921a77 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected @@ -39,6 +39,14 @@ nodes | child_process-test.js:54:25:54:49 | ['/C', ... at(cmd) | | child_process-test.js:54:25:54:49 | ['/C', ... at(cmd) | | child_process-test.js:54:46:54:48 | cmd | +| child_process-test.js:70:9:70:49 | cmd | +| child_process-test.js:70:15:70:38 | url.par ... , true) | +| child_process-test.js:70:15:70:44 | url.par ... ).query | +| child_process-test.js:70:15:70:49 | url.par ... ry.path | +| child_process-test.js:70:25:70:31 | req.url | +| child_process-test.js:70:25:70:31 | req.url | +| child_process-test.js:72:29:72:31 | cmd | +| child_process-test.js:72:29:72:31 | cmd | | execSeries.js:3:20:3:22 | arr | | execSeries.js:6:14:6:16 | arr | | execSeries.js:6:14:6:21 | arr[i++] | @@ -129,6 +137,13 @@ edges | child_process-test.js:53:54:53:56 | cmd | child_process-test.js:53:46:53:57 | ["bar", cmd] | | child_process-test.js:54:46:54:48 | cmd | child_process-test.js:54:25:54:49 | ['/C', ... at(cmd) | | child_process-test.js:54:46:54:48 | cmd | child_process-test.js:54:25:54:49 | ['/C', ... at(cmd) | +| child_process-test.js:70:9:70:49 | cmd | child_process-test.js:72:29:72:31 | cmd | +| child_process-test.js:70:9:70:49 | cmd | child_process-test.js:72:29:72:31 | cmd | +| child_process-test.js:70:15:70:38 | url.par ... , true) | child_process-test.js:70:15:70:44 | url.par ... ).query | +| child_process-test.js:70:15:70:44 | url.par ... ).query | child_process-test.js:70:15:70:49 | url.par ... ry.path | +| child_process-test.js:70:15:70:49 | url.par ... ry.path | child_process-test.js:70:9:70:49 | cmd | +| child_process-test.js:70:25:70:31 | req.url | child_process-test.js:70:15:70:38 | url.par ... , true) | +| child_process-test.js:70:25:70:31 | req.url | child_process-test.js:70:15:70:38 | url.par ... , true) | | execSeries.js:3:20:3:22 | arr | execSeries.js:6:14:6:16 | arr | | execSeries.js:6:14:6:16 | arr | execSeries.js:6:14:6:21 | arr[i++] | | execSeries.js:6:14:6:21 | arr[i++] | execSeries.js:14:24:14:30 | command | @@ -197,6 +212,7 @@ edges | child_process-test.js:54:5:54:50 | cp.spaw ... t(cmd)) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:54:25:54:49 | ['/C', ... at(cmd) | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | | child_process-test.js:59:5:59:39 | cp.exec ... , args) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:50:15:50:17 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | | child_process-test.js:64:3:64:21 | cp.spawn(cmd, args) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:43:15:43:17 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | +| child_process-test.js:72:29:72:31 | cmd | child_process-test.js:70:25:70:31 | req.url | child_process-test.js:72:29:72:31 | cmd | This command depends on $@. | child_process-test.js:70:25:70:31 | req.url | a user-provided value | | execSeries.js:14:41:14:47 | command | execSeries.js:18:34:18:40 | req.url | execSeries.js:14:41:14:47 | command | This command depends on $@. | execSeries.js:18:34:18:40 | req.url | a user-provided value | | other.js:7:33:7:35 | cmd | other.js:5:25:5:31 | req.url | other.js:7:33:7:35 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value | | other.js:8:28:8:30 | cmd | other.js:5:25:5:31 | req.url | other.js:8:28:8:30 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/child_process-test.js b/javascript/ql/test/query-tests/Security/CWE-078/child_process-test.js index c9ece717eb0..c85b4907a3b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/child_process-test.js +++ b/javascript/ql/test/query-tests/Security/CWE-078/child_process-test.js @@ -63,3 +63,12 @@ var server = http.createServer(function(req, res) { function run(cmd, args) { cp.spawn(cmd, args); // NOT OK } + +var util = require("util") + +http.createServer(function(req, res) { + let cmd = url.parse(req.url, true).query.path; + + util.promisify(cp.exec)(cmd); // NOT OK +}); + From fd511422008ecba449f9e55228a926980271d87b Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 15 Apr 2020 20:40:58 +0200 Subject: [PATCH 0149/1298] change succ in storeStep to be a `SourceNode` --- javascript/ql/src/semmle/javascript/Arrays.qll | 16 ++++++++-------- .../ql/src/semmle/javascript/Collections.qll | 12 ++++++------ javascript/ql/src/semmle/javascript/Promises.qll | 14 +++++++------- .../semmle/javascript/dataflow/Configuration.qll | 8 ++++++-- .../semmle/javascript/dataflow/TaintTracking.qll | 9 ++------- 5 files changed, 29 insertions(+), 30 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Arrays.qll b/javascript/ql/src/semmle/javascript/Arrays.qll index 34dafbb5a53..0a3c1865db0 100644 --- a/javascript/ql/src/semmle/javascript/Arrays.qll +++ b/javascript/ql/src/semmle/javascript/Arrays.qll @@ -155,10 +155,10 @@ private module ArrayDataFlow { this.getMethodName() = "unshift" } - override predicate storeStep(DataFlow::Node element, DataFlow::Node obj, string prop) { + override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) { prop = arrayElement() and element = this.getAnArgument() and - obj = this.getReceiver().getALocalSource() + obj.getAMethodCall() = this } } @@ -188,10 +188,10 @@ private module ArrayDataFlow { element = this } - override predicate storeStep(DataFlow::Node element, DataFlow::Node obj, string prop) { + override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) { prop = arrayElement() and element = this.(DataFlow::PropWrite).getRhs() and - this = obj.(DataFlow::SourceNode).getAPropertyWrite() + this = obj.getAPropertyWrite() } } @@ -234,7 +234,7 @@ private module ArrayDataFlow { element = getCallback(0).getParameter(0) } - override predicate storeStep(DataFlow::Node element, DataFlow::Node obj, string prop) { + override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) { this.getMethodName() = "map" and prop = arrayElement() and element = this.getCallback(0).getAReturn() and @@ -254,7 +254,7 @@ private module ArrayDataFlow { private class ArrayCreationStep extends DataFlow::AdditionalFlowStep, DataFlow::Node { ArrayCreationStep() { this instanceof DataFlow::ArrayCreationNode } - override predicate storeStep(DataFlow::Node element, DataFlow::Node obj, string prop) { + override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) { prop = arrayElement() and element = this.(DataFlow::ArrayCreationNode).getAnElement() and obj = this @@ -268,10 +268,10 @@ private module ArrayDataFlow { private class ArraySpliceStep extends DataFlow::AdditionalFlowStep, DataFlow::MethodCallNode { ArraySpliceStep() { this.getMethodName() = "splice" } - override predicate storeStep(DataFlow::Node element, DataFlow::Node obj, string prop) { + override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) { prop = arrayElement() and element = getArgument(2) and - obj = this.getReceiver().getALocalSource() + this = obj.getAMethodCall() } } diff --git a/javascript/ql/src/semmle/javascript/Collections.qll b/javascript/ql/src/semmle/javascript/Collections.qll index f6e4040ac7d..996f825dafb 100644 --- a/javascript/ql/src/semmle/javascript/Collections.qll +++ b/javascript/ql/src/semmle/javascript/Collections.qll @@ -52,9 +52,9 @@ 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, PseudoProperty prop) { none() } + predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, PseudoProperty prop) { none() } - final override predicate storeStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { + final override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { this.store(pred, succ, prop) } @@ -132,8 +132,8 @@ private module CollectionDataFlow { private class SetAdd extends CollectionFlowStep, DataFlow::MethodCallNode { SetAdd() { this.getMethodName() = "add" } - override predicate store(DataFlow::Node element, DataFlow::Node obj, PseudoProperty prop) { - this = obj.(DataFlow::SourceNode).getAMethodCall() and + override predicate store(DataFlow::Node element, DataFlow::SourceNode obj, PseudoProperty prop) { + this = obj.getAMethodCall() and element = this.getArgument(0) and prop = setElement() } @@ -226,8 +226,8 @@ private module CollectionDataFlow { class MapSet extends CollectionFlowStep, DataFlow::MethodCallNode { MapSet() { this.getMethodName() = "set" } - override predicate store(DataFlow::Node element, DataFlow::Node obj, PseudoProperty prop) { - this = obj.(DataFlow::SourceNode).getAMethodCall() and + override predicate store(DataFlow::Node element, DataFlow::SourceNode obj, PseudoProperty prop) { + this = obj.getAMethodCall() and element = this.getArgument(1) and prop = getAPseudoProperty() } diff --git a/javascript/ql/src/semmle/javascript/Promises.qll b/javascript/ql/src/semmle/javascript/Promises.qll index ed7cf13e3b7..8c1c6e5b34b 100644 --- a/javascript/ql/src/semmle/javascript/Promises.qll +++ b/javascript/ql/src/semmle/javascript/Promises.qll @@ -232,9 +232,9 @@ abstract private class PromiseFlowStep 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::SourceNode succ, string prop) { none() } - final override predicate storeStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { + final override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { this.store(pred, succ, prop) } @@ -273,7 +273,7 @@ private module PromiseFlow { PromiseDefitionStep() { this = promise } - override predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) { + override predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { prop = valueProp() and pred = promise.getResolveParameter().getACall().getArgument(0) and succ = this @@ -302,7 +302,7 @@ private module PromiseFlow { CreationStep() { this = promise } - override predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) { + override predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { prop = valueProp() and pred = promise.getValue() and succ = this @@ -368,7 +368,7 @@ private module PromiseFlow { succ = this } - override predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) { + override predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { prop = valueProp() and pred = getCallback([0 .. 1]).getAReturn() and succ = this @@ -402,7 +402,7 @@ private module PromiseFlow { succ = this } - override predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) { + override predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { prop = errorProp() and pred = getCallback(0).getExceptionalReturn() and succ = this @@ -430,7 +430,7 @@ private module PromiseFlow { succ = this } - override predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) { + override predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { prop = errorProp() and pred = getCallback(0).getExceptionalReturn() and succ = this diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index 5c583c38764..0d63f9e4058 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -244,8 +244,11 @@ abstract class Configuration extends string { * EXPERIMENTAL. This API may change in the future. * * Holds if `pred` should be stored in the object `succ` under the property `prop`. + * The object `succ` must be a `DataFlow::SourceNode` for the object wherein the value is stored. */ - predicate isAdditionalStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() } + predicate isAdditionalStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { + none() + } /** * EXPERIMENTAL. This API may change in the future. @@ -540,9 +543,10 @@ abstract class AdditionalFlowStep extends DataFlow::Node { * EXPERIMENTAL. This API may change in the future. * * Holds if `pred` should be stored in the object `succ` under the property `prop`. + * The object `succ` must be a `DataFlow::SourceNode` for the object wherein the value is stored. */ cached - predicate storeStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() } + predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { none() } /** * EXPERIMENTAL. This API may change in the future. diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index 620f4c46cdd..5483d03f65a 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -603,15 +603,10 @@ module TaintTracking { * 3) A `URLSearchParams` object (either `url.searchParams` or `new URLSearchParams(input)`) has a tainted value, * which can be accessed using a `get` or `getAll` call. (See getableUrlPseudoProperty()) */ - override predicate storeStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { + override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { succ = this and ( - ( - prop = "searchParams" or - prop = "hash" or - prop = "search" or - prop = hiddenUrlPseudoProperty() - ) and + prop = ["searchParams", "hash", "search", hiddenUrlPseudoProperty()] and exists(DataFlow::NewNode newUrl | succ = newUrl | newUrl = DataFlow::globalVarRef("URL").getAnInstantiation() and pred = newUrl.getArgument(0) From 90dc14c56ef285ca682dbef778f14dd0090de0a6 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Wed, 15 Apr 2020 18:24:11 -0400 Subject: [PATCH 0150/1298] C++/C#: Fix phantom `Chi` definitions in `PrintSSA` When `PrintSSA.qll` is imported, IR dumps will be annotated with the alias analysis information used during SSA construction. When printing this information, we incorrectly treated instructions at offset -1, which should only be `Phi` instructions, as `Chi` instructions for the instruction at offset 0. This produced phantom annotations, but did not affect the correctness of the actual IR. --- .../cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll | 3 ++- .../cpp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll | 3 ++- .../ir/implementation/unaliased_ssa/internal/PrintSSA.qll | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll index dc02760c7c4..72bb239c153 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll @@ -6,11 +6,12 @@ private import DebugSSA bindingset[offset] private string getKeySuffixForOffset(int offset) { + offset >= 0 and if offset % 2 = 0 then result = "" else result = "_Chi" } bindingset[offset] -private int getIndexForOffset(int offset) { result = offset / 2 } +private int getIndexForOffset(int offset) { offset >= 0 and result = offset / 2 } /** * Property provide that dumps the memory access of each result. Useful for debugging SSA diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll index dc02760c7c4..72bb239c153 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll @@ -6,11 +6,12 @@ private import DebugSSA bindingset[offset] private string getKeySuffixForOffset(int offset) { + offset >= 0 and if offset % 2 = 0 then result = "" else result = "_Chi" } bindingset[offset] -private int getIndexForOffset(int offset) { result = offset / 2 } +private int getIndexForOffset(int offset) { offset >= 0 and result = offset / 2 } /** * Property provide that dumps the memory access of each result. Useful for debugging SSA diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll index dc02760c7c4..72bb239c153 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll @@ -6,11 +6,12 @@ private import DebugSSA bindingset[offset] private string getKeySuffixForOffset(int offset) { + offset >= 0 and if offset % 2 = 0 then result = "" else result = "_Chi" } bindingset[offset] -private int getIndexForOffset(int offset) { result = offset / 2 } +private int getIndexForOffset(int offset) { offset >= 0 and result = offset / 2 } /** * Property provide that dumps the memory access of each result. Useful for debugging SSA From 2264ec714f1339102cd968718ad55906efb3e3e4 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Wed, 15 Apr 2020 18:41:24 -0400 Subject: [PATCH 0151/1298] C++: Better type preservation in `getVariableType()` `getVariableType()` is used to compute the actual semantic type of a variable from its declared type. That's where we handle pointer and function decay for parameters, and it's also where we handle arrays of unknown bound initialized with an initializer of known bound. Previously, even if neither of the above situations applied, the type that we returned was the `getUnspecifiedType()` of the variable. This meant that, for example, `const char* p` would be treated as `char *`. This is inconsistent with how we handle types elsewhere in IR construction, where we preserve typedefs and cv-qualifiers when creating the `CppType` of an `IRVariable`, `Instruction`, or `Operand`. The only visible effect this fix has is to fix the inferred result type for `Phi` instructions for variables affect by this change in `getVariableType()` behavior. Previously, we would see the variable accessed as both `const char*` and as `char*`, so we'd fall back to the canonical pointer type, which is `decltype(nullptr)`. Now, we see the same type for all accesses to the variable, so we use that type as the type of the SSA memory location and as the result type of the `Phi` instruction. --- .../code/cpp/ir/internal/IRUtilities.qll | 11 ++++++---- .../GlobalValueNumbering/ir_gvn.expected | 22 +++++++++---------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/IRUtilities.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/IRUtilities.qll index 53c15663796..6b2b4c918af 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/IRUtilities.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/IRUtilities.qll @@ -23,17 +23,20 @@ Type getVariableType(Variable v) { then result = getDecayedType(declaredType) or - not exists(getDecayedType(declaredType)) and result = declaredType + not exists(getDecayedType(declaredType)) and result = v.getType() else if declaredType instanceof ArrayType and not declaredType.(ArrayType).hasArraySize() then - result = v.getInitializer().getExpr().getUnspecifiedType() + result = v.getInitializer().getExpr().getType() or - not exists(v.getInitializer()) and result = declaredType - else result = declaredType + not exists(v.getInitializer()) and result = v.getType() + else result = v.getType() ) } +/** + * Holds if the database contains a `case` label with the specified minimum and maximum value. + */ predicate hasCaseEdge(SwitchCase switchCase, string minValue, string maxValue) { minValue = switchCase.getExpr().getFullyConverted().getValue() and if exists(switchCase.getEndExpr()) diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected index a492fb47d41..fd6f221c0e8 100644 --- a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected +++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected @@ -433,27 +433,27 @@ test.cpp: #-----| Goto -> Block 3 # 56| Block 3 -# 56| m56_1(decltype(nullptr)) = Phi : from 2:m55_4, from 5:m56_23 +# 56| m56_1(char *) = Phi : from 2:m55_4, from 5:m56_23 # 56| valnum = m56_1, r56_13, r56_20, r56_3, r59_2 -# 56| r56_2(glval) = VariableAddress[ptr] : +# 56| r56_2(glval) = VariableAddress[ptr] : # 56| valnum = r50_1, r55_3, r56_12, r56_19, r56_2, r59_1 -# 56| r56_3(char *) = Load : &:r56_2, m56_1 +# 56| r56_3(char *) = Load : &:r56_2, m56_1 # 56| valnum = m56_1, r56_13, r56_20, r56_3, r59_2 -# 56| r56_4(char) = Load : &:r56_3, ~m49_4 +# 56| r56_4(char) = Load : &:r56_3, ~m49_4 # 56| valnum = r56_14, r56_4, r59_3 -# 56| r56_5(int) = Convert : r56_4 +# 56| r56_5(int) = Convert : r56_4 # 56| valnum = r56_15, r56_5, r59_4 -# 56| r56_6(glval) = VariableAddress[str] : +# 56| r56_6(glval) = VariableAddress[str] : # 56| valnum = r49_6, r53_2, r56_6 -# 56| r56_7(char *) = Load : &:r56_6, m49_7 +# 56| r56_7(char *) = Load : &:r56_6, m49_7 # 56| valnum = m49_7, r49_8, r53_3, r56_7 -# 56| r56_8(char) = Load : &:r56_7, ~m49_9 +# 56| r56_8(char) = Load : &:r56_7, ~m49_9 # 56| valnum = r53_4, r56_8 -# 56| r56_9(int) = Convert : r56_8 +# 56| r56_9(int) = Convert : r56_8 # 56| valnum = r53_5, r56_9 -# 56| r56_10(bool) = CompareNE : r56_5, r56_9 +# 56| r56_10(bool) = CompareNE : r56_5, r56_9 # 56| valnum = unique -# 56| v56_11(void) = ConditionalBranch : r56_10 +# 56| v56_11(void) = ConditionalBranch : r56_10 #-----| False -> Block 6 #-----| True -> Block 4 From a006bd3117b32e256fb5c27754925b8a0827ab72 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Wed, 15 Apr 2020 17:46:00 -0700 Subject: [PATCH 0152/1298] C++: add model-based RemoteFlowSource --- .../code/cpp/models/interfaces/FlowSource.qll | 18 ++++++++++ .../semmle/code/cpp/security/FlowSources.qll | 35 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll create mode 100644 cpp/ql/src/semmle/code/cpp/security/FlowSources.qll diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll new file mode 100644 index 00000000000..4381e776a64 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll @@ -0,0 +1,18 @@ +/** + * Provides a class for modeling functions that return data from potentially untrusted sources. To use + * this QL library, create a QL class extending `DataFlowFunction` with a + * characteristic predicate that selects the function or set of functions you + * are modeling. Within that class, override the predicates provided by + * `RemoteFlowFunction` to match the flow within that function. + */ + +import cpp +import FunctionInputsAndOutputs +import semmle.code.cpp.models.Models + +/** + * A library function which returns data read from a network connection. + */ +abstract class RemoteFlowFunction extends Function { + abstract predicate hasFlowSource(FunctionOutput output); +} diff --git a/cpp/ql/src/semmle/code/cpp/security/FlowSources.qll b/cpp/ql/src/semmle/code/cpp/security/FlowSources.qll new file mode 100644 index 00000000000..b3ddecc3f3c --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/security/FlowSources.qll @@ -0,0 +1,35 @@ +/** + * Provides classes representing various flow sources for taint tracking. + */ + +import cpp +import semmle.code.cpp.ir.dataflow.DataFlow +private import semmle.code.cpp.ir.IR +import semmle.code.cpp.models.interfaces.FlowSource + +/** A data flow source of remote user input. */ +abstract class RemoteFlowSource extends DataFlow::Node { +} + +class FileDescriptorTaintedReturnSource extends RemoteFlowSource { + FileDescriptorTaintedReturnSource() { + exists(RemoteFlowFunction func, CallInstruction instr, FunctionOutput output | + asInstruction() = instr and + instr.getStaticCallTarget() = func and + func.hasFlowSource(output) and + output.isReturnValue() + ) + } +} + +class FileTaintedParameterSource extends RemoteFlowSource { + FileTaintedParameterSource() { + exists(RemoteFlowFunction func, ReadSideEffectInstruction instr, FunctionOutput output | + asInstruction() = instr and + instr.getPrimaryInstruction().(CallInstruction).getStaticCallTarget() = func and + func.hasFlowSource(output) and + output.isParameterDeref(instr.getIndex()) + ) + } +} + From d0e047186a43c7d87133eb15291ced18e37bd4a3 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Wed, 15 Apr 2020 18:01:04 -0700 Subject: [PATCH 0153/1298] C++: add remote flow models for fread and gets --- .../src/semmle/code/cpp/models/implementations/Fread.qll | 7 ++++++- cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Fread.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Fread.qll index 8fdf17ead02..67e1dee4fe9 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Fread.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Fread.qll @@ -1,6 +1,7 @@ import semmle.code.cpp.models.interfaces.Alias +import semmle.code.cpp.models.interfaces.FlowSource -class Fread extends AliasFunction { +class Fread extends AliasFunction, RemoteFlowFunction { Fread() { this.hasGlobalName("fread") } override predicate parameterNeverEscapes(int n) { @@ -11,4 +12,8 @@ class Fread extends AliasFunction { override predicate parameterEscapesOnlyViaReturn(int n) { none() } override predicate parameterIsAlwaysReturned(int n) { none() } + + override predicate hasFlowSource(FunctionOutput output) { + output.isParameterDeref(0) + } } diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll index aa4091fd7f2..c44810546df 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll @@ -3,12 +3,13 @@ import semmle.code.cpp.models.interfaces.Taint import semmle.code.cpp.models.interfaces.ArrayFunction import semmle.code.cpp.models.interfaces.Alias import semmle.code.cpp.models.interfaces.SideEffect +import semmle.code.cpp.models.interfaces.FlowSource /** * The standard functions `gets` and `fgets`. */ class GetsFunction extends DataFlowFunction, TaintFunction, ArrayFunction, AliasFunction, - SideEffectFunction { + SideEffectFunction, RemoteFlowFunction { GetsFunction() { exists(string name | hasGlobalOrStdName(name) | name = "gets" or // gets(str) @@ -42,4 +43,8 @@ class GetsFunction extends DataFlowFunction, TaintFunction, ArrayFunction, Alias buffer = true and mustWrite = true } + + override predicate hasFlowSource(FunctionOutput output) { + output.isParameterDeref(0) + } } From ab120ed7af892d285c57ac9837afcac2a131e29b Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 16 Apr 2020 09:47:45 +0200 Subject: [PATCH 0154/1298] Python: Remove deprecated annotation for old PointsTo::points_to We should only deprecate it when we're ready to deprecate the old refersTo and all the old Object classes --- python/ql/src/semmle/python/pointsto/PointsTo.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/pointsto/PointsTo.qll b/python/ql/src/semmle/python/pointsto/PointsTo.qll index 9bcead16c13..6dade9b8356 100644 --- a/python/ql/src/semmle/python/pointsto/PointsTo.qll +++ b/python/ql/src/semmle/python/pointsto/PointsTo.qll @@ -114,7 +114,7 @@ module PointsTo { /* Backwards compatibility */ cached - deprecated predicate points_to( + predicate points_to( ControlFlowNode f, PointsToContext context, Object obj, ClassObject cls, ControlFlowNode origin ) { exists(ObjectInternal value | From 2acbdecfdb3e48be5fdfab2185523485e0e51477 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 14 Apr 2020 13:19:36 +0100 Subject: [PATCH 0155/1298] C++: Add test cases. --- .../ComparisonWithWiderType.expected | 14 +++++++ .../semmle/ComparisonWithWiderType/test.c | 40 ++++++++++++++++++- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/ComparisonWithWiderType.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/ComparisonWithWiderType.expected index 8927a6bbfc6..a4fce7b3961 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/ComparisonWithWiderType.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/ComparisonWithWiderType.expected @@ -2,3 +2,17 @@ | test.c:9:14:9:18 | ... > ... | Comparison between $@ of type char and $@ of wider type int. | test.c:8:7:8:7 | c | c | test.c:7:17:7:17 | x | x | | test.c:14:14:14:18 | ... < ... | Comparison between $@ of type short and $@ of wider type int. | test.c:13:8:13:8 | s | s | test.c:12:17:12:17 | x | x | | test.c:65:14:65:18 | ... < ... | Comparison between $@ of type short and $@ of wider type int. | test.c:64:8:64:8 | s | s | test.c:63:17:63:17 | x | x | +| test.c:87:14:87:18 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:84:15:84:15 | x | x | +| test.c:91:14:91:23 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type int. | test.c:83:16:83:16 | c | c | test.c:91:18:91:23 | 65280 | 65280 | +| test.c:93:14:93:25 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type int. | test.c:83:16:83:16 | c | c | test.c:93:18:93:25 | 16711680 | 16711680 | +| test.c:95:14:95:27 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:95:18:95:27 | 4278190080 | 4278190080 | +| test.c:97:14:97:27 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:97:19:97:26 | ... & ... | ... & ... | +| test.c:99:14:99:29 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:99:19:99:28 | ... & ... | ... & ... | +| test.c:101:14:101:31 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:101:19:101:30 | ... & ... | ... & ... | +| test.c:103:14:103:33 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:103:19:103:32 | ... & ... | ... & ... | +| test.c:105:14:105:25 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:105:19:105:24 | ... >> ... | ... >> ... | +| test.c:107:14:107:26 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:107:19:107:25 | ... >> ... | ... >> ... | +| test.c:109:14:109:26 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:109:19:109:25 | ... >> ... | ... >> ... | +| test.c:111:14:111:36 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:111:19:111:35 | ... >> ... | ... >> ... | +| test.c:113:14:113:39 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:113:19:113:38 | ... >> ... | ... >> ... | +| test.c:115:14:115:41 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:115:19:115:40 | ... >> ... | ... >> ... | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test.c b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test.c index 5802ca3eb4f..8766d5dcadc 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test.c @@ -75,4 +75,42 @@ extern const int const256; void test11() { short s; for(s = 0; s < const256; ++s) {} -} \ No newline at end of file +} + +unsigned int get_a_uint(); + +void test12() { + unsigned char c; + unsigned int x; + + x = get_a_uint(); + for (c = 0; c < x; c++) {} // BAD + x = get_a_uint(); + for (c = 0; c < 0xFF; c++) {} // GOOD + x = get_a_uint(); + for (c = 0; c < 0xFF00; c++) {} // BAD + x = get_a_uint(); + for (c = 0; c < 0xFF0000; c++) {} // BAD + x = get_a_uint(); + for (c = 0; c < 0xFF000000; c++) {} // BAD + x = get_a_uint(); + for (c = 0; c < (x & 0xFF); c++) {} // GOOD [FALSE POSITIVE] + x = get_a_uint(); + for (c = 0; c < (x & 0xFF00); c++) {} // BAD + x = get_a_uint(); + for (c = 0; c < (x & 0xFF0000); c++) {} // BAD + x = get_a_uint(); + for (c = 0; c < (x & 0xFF000000); c++) {} // BAD + x = get_a_uint(); + for (c = 0; c < (x >> 8); c++) {} // BAD + x = get_a_uint(); + for (c = 0; c < (x >> 16); c++) {} // BAD + x = get_a_uint(); + for (c = 0; c < (x >> 24); c++) {} // GOOD (assuming 32-bit ints) [FALSE POSITIVE] + x = get_a_uint(); + for (c = 0; c < ((x & 0xFF00) >> 8); c++) {} // GOOD [FALSE POSITIVE] + x = get_a_uint(); + for (c = 0; c < ((x & 0xFF0000) >> 16); c++) {} // GOOD [FALSE POSITIVE] + x = get_a_uint(); + for (c = 0; c < ((x & 0xFF000000) >> 24); c++) {} // GOOD [FALSE POSITIVE] +} From 24d7446976cc2d5da8d714a0a4efb7f80b046ed8 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 14 Apr 2020 13:56:58 +0100 Subject: [PATCH 0156/1298] C++: Basic model of '&' and '>>' in SimpleRangeAnalysis. --- .../cpp/rangeanalysis/SimpleRangeAnalysis.qll | 113 +++++++++++++++--- .../ComparisonWithWiderType.expected | 5 - .../semmle/ComparisonWithWiderType/test.c | 10 +- 3 files changed, 102 insertions(+), 26 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll index 22e5f5ac83e..bf592dcfbe7 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll @@ -118,36 +118,74 @@ private string getValue(Expr e) { ) } +/** + * A bitwise `&` expression in which both operands are unsigned, or are effectively + * unsigned due to being a non-negative constant. + */ +private class UnsignedBitwiseAndExpr extends BitwiseAndExpr { + UnsignedBitwiseAndExpr() { + ( + getLeftOperand().getType().getUnderlyingType().(IntegralType).isUnsigned() or + getLeftOperand().getValue().toInt() >= 0 + ) and + ( + getRightOperand().getType().getUnderlyingType().(IntegralType).isUnsigned() or + getRightOperand().getValue().toInt() >= 0 + ) + } +} + /** Set of expressions which we know how to analyze. */ private predicate analyzableExpr(Expr e) { // The type of the expression must be arithmetic. We reuse the logic in // `exprMinVal` to check this. exists(exprMinVal(e)) and ( - exists(getValue(e).toFloat()) or - e instanceof UnaryPlusExpr or - e instanceof UnaryMinusExpr or - e instanceof MinExpr or - e instanceof MaxExpr or - e instanceof ConditionalExpr or - e instanceof AddExpr or - e instanceof SubExpr or - e instanceof AssignExpr or - e instanceof AssignAddExpr or - e instanceof AssignSubExpr or - e instanceof CrementOperation or - e instanceof RemExpr or - e instanceof CommaExpr or - e instanceof StmtExpr or + exists(getValue(e).toFloat()) + or + e instanceof UnaryPlusExpr + or + e instanceof UnaryMinusExpr + or + e instanceof MinExpr + or + e instanceof MaxExpr + or + e instanceof ConditionalExpr + or + e instanceof AddExpr + or + e instanceof SubExpr + or + e instanceof AssignExpr + or + e instanceof AssignAddExpr + or + e instanceof AssignSubExpr + or + e instanceof CrementOperation + or + e instanceof RemExpr + or + e instanceof CommaExpr + or + e instanceof StmtExpr + or // A conversion is analyzable, provided that its child has an arithmetic // type. (Sometimes the child is a reference type, and so does not get // any bounds.) Rather than checking whether the type of the child is // arithmetic, we reuse the logic that is already encoded in // `exprMinVal`. - exists(exprMinVal(e.(Conversion).getExpr())) or + exists(exprMinVal(e.(Conversion).getExpr())) + or // Also allow variable accesses, provided that they have SSA // information. exists(RangeSsaDefinition def, StackVariable v | e = def.getAUse(v)) + or + e instanceof UnsignedBitwiseAndExpr + or + // `>>` by a constant + exists(e.(RShiftExpr).getRightOperand().getValue()) ) } @@ -245,6 +283,19 @@ private predicate exprDependsOnDef(Expr e, RangeSsaDefinition srcDef, StackVaria or exists(Conversion convExpr | e = convExpr | exprDependsOnDef(convExpr.getExpr(), srcDef, srcVar)) or + // unsigned `&` + exists(UnsignedBitwiseAndExpr andExpr | + andExpr = e and + exprDependsOnDef(andExpr.getAnOperand(), srcDef, srcVar) + ) + or + // `>>` by a constant + exists(RShiftExpr rs | + rs = e and + exists(rs.getRightOperand().getValue()) and + exprDependsOnDef(rs.getLeftOperand(), srcDef, srcVar) + ) + or e = srcDef.getAUse(srcVar) } @@ -641,6 +692,20 @@ private float getLowerBoundsImpl(Expr expr) { exists(RangeSsaDefinition def, StackVariable v | expr = def.getAUse(v) | result = getDefLowerBounds(def, v) ) + or + // unsigned `&` (tighter bounds may exist) + exists(UnsignedBitwiseAndExpr andExpr | + andExpr = expr and + result = 0.0 + ) + or + // `>>` by a constant + exists(RShiftExpr rsExpr, float left, int right | + rsExpr = expr and + left = getFullyConvertedLowerBounds(rsExpr.getLeftOperand()) and + right = rsExpr.getRightOperand().getValue().toInt() and + result = left / 2.pow(right) + ) } /** Only to be called by `getTruncatedUpperBounds`. */ @@ -794,6 +859,22 @@ private float getUpperBoundsImpl(Expr expr) { exists(RangeSsaDefinition def, StackVariable v | expr = def.getAUse(v) | result = getDefUpperBounds(def, v) ) + or + // unsigned `&` (tighter bounds may exist) + exists(UnsignedBitwiseAndExpr andExpr, float left, float right | + andExpr = expr and + left = getFullyConvertedUpperBounds(andExpr.getLeftOperand()) and + right = getFullyConvertedUpperBounds(andExpr.getRightOperand()) and + result = left.minimum(right) + ) + or + // `>>` by a constant + exists(RShiftExpr rsExpr, float left, int right | + rsExpr = expr and + left = getFullyConvertedUpperBounds(rsExpr.getLeftOperand()) and + right = rsExpr.getRightOperand().getValue().toInt() and + result = left / 2.pow(right) + ) } /** diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/ComparisonWithWiderType.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/ComparisonWithWiderType.expected index a4fce7b3961..a822d1dfbf6 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/ComparisonWithWiderType.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/ComparisonWithWiderType.expected @@ -6,13 +6,8 @@ | test.c:91:14:91:23 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type int. | test.c:83:16:83:16 | c | c | test.c:91:18:91:23 | 65280 | 65280 | | test.c:93:14:93:25 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type int. | test.c:83:16:83:16 | c | c | test.c:93:18:93:25 | 16711680 | 16711680 | | test.c:95:14:95:27 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:95:18:95:27 | 4278190080 | 4278190080 | -| test.c:97:14:97:27 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:97:19:97:26 | ... & ... | ... & ... | | test.c:99:14:99:29 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:99:19:99:28 | ... & ... | ... & ... | | test.c:101:14:101:31 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:101:19:101:30 | ... & ... | ... & ... | | test.c:103:14:103:33 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:103:19:103:32 | ... & ... | ... & ... | | test.c:105:14:105:25 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:105:19:105:24 | ... >> ... | ... >> ... | | test.c:107:14:107:26 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:107:19:107:25 | ... >> ... | ... >> ... | -| test.c:109:14:109:26 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:109:19:109:25 | ... >> ... | ... >> ... | -| test.c:111:14:111:36 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:111:19:111:35 | ... >> ... | ... >> ... | -| test.c:113:14:113:39 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:113:19:113:38 | ... >> ... | ... >> ... | -| test.c:115:14:115:41 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:115:19:115:40 | ... >> ... | ... >> ... | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test.c b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test.c index 8766d5dcadc..c33b28a1a76 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test.c @@ -94,7 +94,7 @@ void test12() { x = get_a_uint(); for (c = 0; c < 0xFF000000; c++) {} // BAD x = get_a_uint(); - for (c = 0; c < (x & 0xFF); c++) {} // GOOD [FALSE POSITIVE] + for (c = 0; c < (x & 0xFF); c++) {} // GOOD x = get_a_uint(); for (c = 0; c < (x & 0xFF00); c++) {} // BAD x = get_a_uint(); @@ -106,11 +106,11 @@ void test12() { x = get_a_uint(); for (c = 0; c < (x >> 16); c++) {} // BAD x = get_a_uint(); - for (c = 0; c < (x >> 24); c++) {} // GOOD (assuming 32-bit ints) [FALSE POSITIVE] + for (c = 0; c < (x >> 24); c++) {} // GOOD (assuming 32-bit ints) x = get_a_uint(); - for (c = 0; c < ((x & 0xFF00) >> 8); c++) {} // GOOD [FALSE POSITIVE] + for (c = 0; c < ((x & 0xFF00) >> 8); c++) {} // GOOD x = get_a_uint(); - for (c = 0; c < ((x & 0xFF0000) >> 16); c++) {} // GOOD [FALSE POSITIVE] + for (c = 0; c < ((x & 0xFF0000) >> 16); c++) {} // GOOD x = get_a_uint(); - for (c = 0; c < ((x & 0xFF000000) >> 24); c++) {} // GOOD [FALSE POSITIVE] + for (c = 0; c < ((x & 0xFF000000) >> 24); c++) {} // GOOD } From 2d8770d17c3b767a0c70a7e95643752c2e65e7ae Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Thu, 16 Apr 2020 14:02:55 +0200 Subject: [PATCH 0157/1298] Python: Fix remaining deprecation warnings. --- python/ql/src/Resources/FileOpen.qll | 2 +- python/ql/src/semmle/python/dataflow/TaintTracking.qll | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/python/ql/src/Resources/FileOpen.qll b/python/ql/src/Resources/FileOpen.qll index 07b901dad69..f4d1f30723a 100644 --- a/python/ql/src/Resources/FileOpen.qll +++ b/python/ql/src/Resources/FileOpen.qll @@ -79,7 +79,7 @@ predicate def_is_open(EssaDefinition def, ControlFlowNode open) { passes_open_files(refinement) ) or - exists(PyNodeRefinement refinement | refinement = def | + exists(EssaNodeRefinement refinement | refinement = def | not closes_file(def) and not wraps_file(refinement.getDefiningNode(), refinement.getInput()) and var_is_open(refinement.getInput(), open) diff --git a/python/ql/src/semmle/python/dataflow/TaintTracking.qll b/python/ql/src/semmle/python/dataflow/TaintTracking.qll index 88ef3c4e4fc..f1966dd2efc 100755 --- a/python/ql/src/semmle/python/dataflow/TaintTracking.qll +++ b/python/ql/src/semmle/python/dataflow/TaintTracking.qll @@ -155,7 +155,7 @@ abstract class TaintKind extends string { * For example, if this were a kind of string taint * the `result` would be `theStrType()`. */ - ClassValue getType() { result.(ClassObjectInternal).getSource() = this.getClass() } + ClassValue getType() { none() } /** * Gets the boolean values (may be one, neither, or both) that @@ -180,7 +180,10 @@ abstract class TaintKind extends string { TaintKind getTaintForIteration() { none() } predicate flowStep(DataFlow::Node fromnode, DataFlow::Node tonode, string edgeLabel) { - this.additionalFlowStepVar(fromnode.asVariable(), tonode.asVariable()) and + exists(DataFlowExtension::DataFlowVariable v | + v = fromnode.asVariable() and + v.getASuccessorVariable() = tonode.asVariable() + ) and edgeLabel = "custom taint variable step" } } From 1959480b78d6f1a7df111e9e938a7cae2c35cccc Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 14 Apr 2020 15:58:09 +0200 Subject: [PATCH 0158/1298] C#: Field-flow summaries for library code --- csharp/ql/src/semmle/code/csharp/Caching.qll | 2 + .../csharp/dataflow/LibraryTypeDataFlow.qll | 293 ++++--- .../internal/ControlFlowReachability.qll | 11 +- .../dataflow/internal/DataFlowDispatch.qll | 5 +- .../dataflow/internal/DataFlowPrivate.qll | 742 +++++++++++------- .../dataflow/internal/DataFlowPublic.qll | 74 +- .../dataflow/internal/DelegateDataFlow.qll | 3 + .../internal/TaintTrackingPrivate.qll | 17 +- .../src/semmle/code/csharp/exprs/Access.qll | 12 +- .../semmle/code/csharp/frameworks/JsonNET.qll | 2 +- .../csharp7/LocalTaintFlow.expected | 26 +- .../dataflow/global/DataFlowPath.expected | 8 +- .../global/TaintTrackingPath.expected | 98 ++- .../library/LibraryTypeDataFlow.expected | 9 +- .../dataflow/library/LibraryTypeDataFlow.ql | 29 +- .../dataflow/local/DataFlowStep.expected | 18 +- .../dataflow/local/TaintTrackingStep.expected | 297 ++++--- 17 files changed, 978 insertions(+), 668 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/Caching.qll b/csharp/ql/src/semmle/code/csharp/Caching.qll index e9e8f44c818..4443ec9bc7c 100644 --- a/csharp/ql/src/semmle/code/csharp/Caching.qll +++ b/csharp/ql/src/semmle/code/csharp/Caching.qll @@ -68,6 +68,8 @@ module Stages { or exists(any(DataFlow::Node n).getType()) or + exists(any(DataFlow::Node n).getTypeBound()) + or exists(any(DataFlow::Node n).getLocation()) or exists(any(DataFlow::Node n).toString()) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll b/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll index 26b6e5f7b96..f3c061403f5 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll @@ -16,113 +16,49 @@ private import semmle.code.csharp.frameworks.system.threading.Tasks private import semmle.code.csharp.frameworks.system.Web private import semmle.code.csharp.frameworks.system.web.ui.WebControls private import semmle.code.csharp.frameworks.system.Xml +private import semmle.code.csharp.dataflow.internal.DataFlowPublic +private import semmle.code.csharp.dataflow.internal.DelegateDataFlow -cached -private module Cached { - /** - * INTERNAL: Do not use. - * - * Holds if `source` can flow to `sink` using a call to a library - * callable. - */ - cached - predicate libraryFlow(Expr source, Expr sink, boolean preservesValue) { - exists(LibraryTypeDataFlow ltdf, CallableFlowSource csource, CallableFlowSink csink, Call c | - source = csource.getSource(c) and - ltdf.callableFlow(csource, csink, c.getTarget().getSourceDeclaration(), preservesValue) and - sink = csink.getSink(c) - ) - } +private newtype TAccessPath = + TNilAccessPath() or + TAccessPathConsNil(Content c) - /** - * INTERNAL: Do not use. - * - * Holds if `source` can flow to the `out`/`ref` argument `outRef` using a call to a library - * callable. - */ - cached - predicate libraryFlowOutRef(MethodCall mc, Expr source, Parameter outRef, boolean preservesValue) { - exists( - LibraryTypeDataFlow ltdf, CallableFlowSource csource, CallableFlowSinkArg csink, Method sm - | - source = csource.getSource(mc) and - mc.getTarget().getAParameter() = outRef and - sm = mc.getTarget().getSourceDeclaration() and - ltdf.callableFlow(csource, csink, sm, preservesValue) and - csink = getFlowSinkArg(sm, outRef.getPosition()) - ) - } +/** An access path of length 0 or 1. */ +class AccessPath extends TAccessPath { + /** Gets the head of this access path, if any. */ + Content getHead() { this = TAccessPathConsNil(result) } - /** - * INTERNAL: Do not use. - * - * Holds if output from the `i`th delegate argument of `call` can flow to `sink`, using - * the library target `callable`. - */ - cached - predicate libraryFlowDelegateCallOut( - Call call, Callable callable, Expr sink, boolean preservesValue, int i - ) { - exists(LibraryTypeDataFlow ltdf, CallableFlowSourceDelegateArg csource, CallableFlowSink csink | - ltdf.callableFlow(csource, csink, callable, preservesValue) and - call.getTarget().getSourceDeclaration() = callable and - csource = getDelegateFlowSourceArg(callable, i) and - sink = csink.getSink(call) - ) - } + /** Holds if this access path contains content `c`. */ + predicate contains(Content c) { this = TAccessPathConsNil(c) } - /** - * INTERNAL: Do not use. - * - * Holds if `source` can flow to the `i`th parameter of the delegate at argument - * `j`. The call `call` is the call in which `sink` is an argument and`callable` - * is the library target. - */ - cached - predicate libraryFlowDelegateCallIn( - Call call, Callable callable, Expr source, boolean preservesValue, int i, int j - ) { - exists(LibraryTypeDataFlow ltdf, CallableFlowSource csource, CallableFlowSinkDelegateArg csink | - ltdf.callableFlow(csource, csink, callable, preservesValue) and - call.getTarget().getSourceDeclaration() = callable and - csink = getDelegateFlowSinkArg(callable, j, i) and - source = csource.getSource(call) - ) - } - - /** - * INTERNAL: Do not use. - * - * Holds if output from the `i`th delegate argument of `call` can flow to the `j`th parameter - * of the of delegate at argument `k`, using the library target `callable`. - */ - cached - predicate libraryFlowDelegateCallOutIn( - Call call, Callable callable, boolean preservesValue, int i, int j, int k - ) { - exists( - LibraryTypeDataFlow ltdf, CallableFlowSourceDelegateArg csource, - CallableFlowSinkDelegateArg csink - | - ltdf.callableFlow(csource, csink, callable, preservesValue) and - call.getTarget().getSourceDeclaration() = callable and - csource = getDelegateFlowSourceArg(callable, i) and - csink = getDelegateFlowSinkArg(callable, k, j) - ) + /** Gets a textual representation of this access path. */ + string toString() { + result = this.getHead().toString() + or + this = TNilAccessPath() and + result = "" } } -import Cached +/** Provides predicates for constructing access paths. */ +module AccessPath { + /** Gets the empty access path. */ + AccessPath empty() { result = TNilAccessPath() } + + /** Gets a singleton property access path. */ + AccessPath property(Property p) { + result = TAccessPathConsNil(any(PropertyContent c | c.getProperty() = p.getSourceDeclaration())) + } +} /** An unbound callable. */ -library class SourceDeclarationCallable extends Callable { - SourceDeclarationCallable() { this = getSourceDeclaration() } +class SourceDeclarationCallable extends Callable { + SourceDeclarationCallable() { this = this.getSourceDeclaration() } } /** An unbound method. */ -library class SourceDeclarationMethod extends SourceDeclarationCallable, Method { } +class SourceDeclarationMethod extends SourceDeclarationCallable, Method { } -// Internal representation of callable flow sources private newtype TCallableFlowSource = TCallableFlowSourceQualifier() or TCallableFlowSourceArg(int i) { hasArgumentPosition(_, i) } or @@ -160,83 +96,119 @@ private predicate hasDelegateArgumentPosition2(SourceDeclarationCallable c, int ) } -/** A flow source in a call to a library callable. */ +/** A flow source specification. */ class CallableFlowSource extends TCallableFlowSource { - /** Gets a textual representation of this flow source. */ + /** Gets a textual representation of this flow source specification. */ string toString() { none() } /** Gets the source of flow for call `c`, if any. */ Expr getSource(Call c) { none() } + + /** + * Gets the type of the source for call `c`. Unlike `getSource()`, this + * is defined for all flow source specifications. + */ + Type getSourceType(Call c) { result = this.getSource(c).getType() } } -/** A flow source in a call to a library callable: qualifier. */ +/** A flow source specification: (method call) qualifier. */ class CallableFlowSourceQualifier extends CallableFlowSource, TCallableFlowSourceQualifier { override string toString() { result = "qualifier" } override Expr getSource(Call c) { result = c.getChild(-1) } } -/** A flow source in a call to a library callable: argument. */ +/** A flow source specification: (method call) argument. */ class CallableFlowSourceArg extends CallableFlowSource, TCallableFlowSourceArg { - override string toString() { result = "argument " + this.getArgumentIndex() } + private int i; + + CallableFlowSourceArg() { this = TCallableFlowSourceArg(i) } /** Gets the index of this argument. */ - int getArgumentIndex() { this = TCallableFlowSourceArg(result) } + int getArgumentIndex() { result = i } - override Expr getSource(Call c) { result = c.getArgument(getArgumentIndex()) } + override string toString() { result = "argument " + i } + + override Expr getSource(Call c) { result = c.getArgument(i) } } -/** A flow source in a call to a library callable: output from delegate argument. */ +/** A flow source specification: output from delegate argument. */ class CallableFlowSourceDelegateArg extends CallableFlowSource, TCallableFlowSourceDelegateArg { - override string toString() { result = "output from argument " + getArgumentIndex().toString() } + private int i; + + CallableFlowSourceDelegateArg() { this = TCallableFlowSourceDelegateArg(i) } /** Gets the index of this delegate argument. */ - int getArgumentIndex() { this = TCallableFlowSourceDelegateArg(result) } + int getArgumentIndex() { result = i } + + override string toString() { result = "output from argument " + i } override Expr getSource(Call c) { none() } + + override Type getSourceType(Call c) { result = c.getArgument(i).getType() } } -// Internal representation of callable flow sinks private newtype TCallableFlowSink = TCallableFlowSinkQualifier() or TCallableFlowSinkReturn() or TCallableFlowSinkArg(int i) { exists(SourceDeclarationCallable c | exists(c.getParameter(i))) } or TCallableFlowSinkDelegateArg(int i, int j) { hasDelegateArgumentPosition2(_, i, j) } -/** A flow sink in a call to a library callable. */ +/** A flow sink specification. */ class CallableFlowSink extends TCallableFlowSink { - /** Gets a textual representation of this flow sink. */ + /** Gets a textual representation of this flow sink specification. */ string toString() { none() } /** Gets the sink of flow for call `c`, if any. */ Expr getSink(Call c) { none() } + + /** + * Gets the type of the sink for call `c`. Unlik `getSink()`, this is defined + * for all flow sink specifications. + */ + Type getSinkType(Call c) { result = this.getSink(c).getType() } } -/** A flow sink in a call to a library callable: qualifier. */ +/** A flow sink specification: (method call) qualifier. */ class CallableFlowSinkQualifier extends CallableFlowSink, TCallableFlowSinkQualifier { override string toString() { result = "qualifier" } override Expr getSink(Call c) { result = c.getChild(-1) } } -/** A flow sink in a call to a library callable: return value. */ +/** A flow sink specification: return value. */ class CallableFlowSinkReturn extends CallableFlowSink, TCallableFlowSinkReturn { override string toString() { result = "return" } override Expr getSink(Call c) { result = c } } -/** The flow sink in an argument to a call to a library method. */ +/** A flow sink specification: (method call) argument. */ class CallableFlowSinkArg extends CallableFlowSink, TCallableFlowSinkArg { - override string toString() { result = "argument " + this.getArgumentIndex() } + private int i; + + CallableFlowSinkArg() { this = TCallableFlowSinkArg(i) } /** Gets the index of this `out`/`ref` argument. */ - int getArgumentIndex() { this = TCallableFlowSinkArg(result) } + int getArgumentIndex() { result = i } + + /** Gets the `out`/`ref` argument of method call `mc` matching this specification. */ + Expr getArgument(MethodCall mc) { + exists(Parameter p | + p = mc.getTarget().getParameter(i) and + p.isOutOrRef() and + result = mc.getArgumentForParameter(p) + ) + } + + override string toString() { result = "argument " + i } override Expr getSink(Call c) { // The uses of the `i`th argument are the actual sinks none() } + + override Type getSinkType(Call c) { result = this.getArgument(c).getType() } } /** Gets the flow source for argument `i` of callable `callable`. */ @@ -245,12 +217,6 @@ private CallableFlowSourceArg getFlowSourceArg(SourceDeclarationCallable callabl hasArgumentPosition(callable, i) } -/** Gets the flow sink for argument `i` of callable `callable`. */ -private CallableFlowSinkArg getFlowSinkArg(SourceDeclarationCallable callable, int i) { - i = result.getArgumentIndex() and - hasArgumentPosition(callable, i) -} - /** Gets the flow source for argument `i` of delegate `callable`. */ private CallableFlowSourceDelegateArg getDelegateFlowSourceArg( SourceDeclarationCallable callable, int i @@ -267,30 +233,40 @@ private CallableFlowSinkDelegateArg getDelegateFlowSinkArg( hasDelegateArgumentPosition2(callable, i, j) } -/** The flow sink in a call to a library callable: parameter of a delegate argument. */ +/** A flow sink specification: parameter of a delegate argument. */ class CallableFlowSinkDelegateArg extends CallableFlowSink, TCallableFlowSinkDelegateArg { - override string toString() { - result = - "parameter " + getDelegateParameterIndex() + " of argument " + getDelegateIndex().toString() - } + private int i; + private int j; + + CallableFlowSinkDelegateArg() { this = TCallableFlowSinkDelegateArg(i, j) } + + /** Gets the index of the delegate argument. */ + int getDelegateIndex() { result = i } + + /** Gets the index of the delegate parameter. */ + int getDelegateParameterIndex() { result = j } + + override string toString() { result = "parameter " + j + " of argument " + i } override Expr getSink(Call c) { // The uses of the `j`th parameter are the actual sinks none() } - /** Gets the index of the delegate argument. */ - int getDelegateIndex() { this = TCallableFlowSinkDelegateArg(result, _) } - - /** Gets the index of the delegate parameter. */ - int getDelegateParameterIndex() { this = TCallableFlowSinkDelegateArg(_, result) } + override Type getSinkType(Call c) { + result = + c + .getArgument(i) + .(DelegateArgumentToLibraryCallable) + .getDelegateType() + .getParameter(j) + .getType() + } } -/** - * A specification of data flow for a library (non-source code) type. - */ +/** A specification of data flow for a library (non-source code) type. */ abstract class LibraryTypeDataFlow extends Type { - LibraryTypeDataFlow() { this = getSourceDeclaration() } + LibraryTypeDataFlow() { this = this.getSourceDeclaration() } /** * Holds if data may flow from `source` to `sink` when calling callable `c`. @@ -300,10 +276,27 @@ abstract class LibraryTypeDataFlow extends Type { * to `x.ToString()` when `x` is a `string`, but not from `x` to `x.ToLower()`. */ pragma[nomagic] - abstract predicate callableFlow( + predicate callableFlow( CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, boolean preservesValue - ); + ) { + none() + } + + /** + * Holds if data may flow from `source` to `sink` when calling callable `c`. + * + * `sourceAp` describes the contents of `source` that flows to `sink` + * (if any), and `sinkContent` describes the contents of `sink` that it + * flows to (if any). + */ + pragma[nomagic] + predicate callableFlow( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c + ) { + none() + } } /** Data flow for `System.Int32`. */ @@ -614,38 +607,20 @@ class SystemTextStringBuilderFlow extends LibraryTypeDataFlow, SystemTextStringB } /** Data flow for `System.Lazy<>`. */ -class SystemLazyFlow extends LibraryTypeDataFlow { - SystemLazyFlow() { this instanceof SystemLazyClass } - +class SystemLazyFlow extends LibraryTypeDataFlow, SystemLazyClass { override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue - ) { - ( - constructorFlow(source, sink, c) - or - exists(Property p | - propertyFlow(p) and - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - c = p.getGetter() - ) - ) and - preservesValue = true - } - - private predicate constructorFlow( - CallableFlowSourceDelegateArg source, CallableFlowSink sink, Constructor c + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c ) { exists(SystemFuncDelegateType t, int i | t.getNumberOfTypeParameters() = 1 | - c.getDeclaringType() = this and + c.(Constructor).getDeclaringType() = this and c.getParameter(i).getType().getSourceDeclaration() = t and source = getDelegateFlowSourceArg(c, i) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::property(this.getValueProperty()) ) } - - private predicate propertyFlow(Property p) { p = this.(SystemLazyClass).getValueProperty() } } /** diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll index b05595c32c3..2b09436f27d 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll @@ -173,15 +173,16 @@ abstract class ControlFlowReachabilityConfiguration extends string { * Holds if there is a control-flow path from `cfn1` to `cfn2`, where `cfn1` is a * control-flow node for `e1` and `cfn2` is a control-flow node for `e2`. */ + pragma[nomagic] predicate hasExprPath(Expr e1, ControlFlow::Node cfn1, Expr e2, ControlFlow::Node cfn2) { exists(ControlFlow::BasicBlock bb, boolean isSuccessor, int i, int j | this.reachesBasicBlockExprBase(e1, e2, _, _, isSuccessor, cfn1, i, bb) and cfn2 = bb.getNode(j) and cfn2 = e2.getAControlFlowNode() | - isSuccessor = true and j > i + isSuccessor = true and j >= i or - isSuccessor = false and i > j + isSuccessor = false and i >= j ) or exists(ControlFlow::BasicBlock bb | @@ -195,6 +196,7 @@ abstract class ControlFlowReachabilityConfiguration extends string { * Holds if there is a control-flow path from `cfn` to `cfnDef`, where `cfn` is a * control-flow node for `e` and `cfnDef` is a control-flow node for `def`. */ + pragma[nomagic] predicate hasDefPath( Expr e, ControlFlow::Node cfn, AssignableDefinition def, ControlFlow::Node cfnDef ) { @@ -203,9 +205,9 @@ abstract class ControlFlowReachabilityConfiguration extends string { cfnDef = bb.getNode(j) and def.getAControlFlowNode() = cfnDef | - isSuccessor = true and j > i + isSuccessor = true and j >= i or - isSuccessor = false and i > j + isSuccessor = false and i >= j ) or exists(ControlFlow::BasicBlock bb | @@ -219,6 +221,7 @@ abstract class ControlFlowReachabilityConfiguration extends string { * Holds if there is a control-flow path from `n1` to `n2`. `n2` is either an * expression node or an SSA definition node. */ + pragma[nomagic] predicate hasNodePath(ExprNode n1, Node n2) { exists(Expr e1, ControlFlow::Node cfn1, Expr e2, ControlFlow::Node cfn2 | this.hasExprPath(e1, cfn1, e2, cfn2) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll index 1e1353279a1..fdf0480c8ef 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll @@ -346,11 +346,14 @@ class ImplicitDelegateDataFlowCall extends DelegateDataFlowCall, TImplicitDelega /** Gets the number of parameters of the supplied delegate. */ int getNumberOfDelegateParameters() { result = arg.getDelegateType().getNumberOfParameters() } + /** Gets the type of the `i`th parameter of the supplied delegate. */ + Type getDelegateParameterType(int i) { result = arg.getDelegateType().getParameter(i).getType() } + /** Gets the return type of the supplied delegate. */ Type getDelegateReturnType() { result = arg.getDelegateType().getReturnType() } override DotNet::Callable getARuntimeTarget(CallContext::CallContext cc) { - result = cfn.getElement().(DelegateArgumentToLibraryCallable).getARuntimeTarget(cc) + result = arg.getARuntimeTarget(cc) } override ControlFlow::Nodes::ElementNode getControlFlowNode() { result = cfn } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index 4a6693fbebf..5fdf8248de9 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -81,9 +81,6 @@ module LocalFlow { ) { exactScope = false and ( - // Flow using library code - libraryFlow(e1, e2, scope, isSuccessor, true) - or e1 = e2.(ParenthesizedExpr).getExpr() and scope = e2 and isSuccessor = true @@ -244,39 +241,9 @@ module LocalFlow { nodeTo = TImplicitCapturedArgumentNode(call, def.getSourceVariable().getAssignable()) ) } - - private Expr getALibraryFlowParentFrom(Expr exprFrom, Expr exprTo, boolean preservesValue) { - libraryFlow(exprFrom, exprTo, preservesValue) and - result = exprFrom - or - result.getAChildExpr() = getALibraryFlowParentFrom(exprFrom, exprTo, preservesValue) - } - - private Expr getALibraryFlowParentTo(Expr exprFrom, Expr exprTo, boolean preservesValue) { - libraryFlow(exprFrom, exprTo, preservesValue) and - result = exprTo - or - exists(Expr mid | mid = getALibraryFlowParentTo(exprFrom, exprTo, preservesValue) | - result.getAChildExpr() = mid and - not mid = getALibraryFlowParentFrom(exprFrom, exprTo, preservesValue) - ) - } - - pragma[noinline] - predicate libraryFlow( - Expr exprFrom, Expr exprTo, Expr scope, boolean isSuccessor, boolean preservesValue - ) { - // To not pollute the definitions in `LibraryTypeDataFlow.qll` with syntactic scope, - // simply use the nearest common parent expression for `exprFrom` and `exprTo` - scope = getALibraryFlowParentFrom(exprFrom, exprTo, preservesValue) and - scope = getALibraryFlowParentTo(exprFrom, exprTo, preservesValue) and - // Similarly, for simplicity allow following both forwards and backwards edges from - // `exprFrom` to `exprTo` - (isSuccessor = true or isSuccessor = false) - } } -/** An argument of a C# call. */ +/** An argument of a C# call (including qualifier arguments). */ private class Argument extends Expr { private Expr call; private int arg; @@ -292,39 +259,85 @@ private class Argument extends Expr { this = call.(DelegateCall).getArgument(arg) } - /** Holds if this expression is the `i`th argument of `c`. */ + /** + * Holds if this expression is the `i`th argument of `c`. + * + * Qualifier arguments have index `-1`. + */ predicate isArgumentOf(Expr c, int i) { c = call and i = arg } } /** - * Holds if `e` is an assignment of `src` to a non-static field or field-like - * property `f` of `q`. + * Holds if `e` is an assignment of `src` to field or property `c` of `q`. */ -private predicate instanceFieldLikeAssign(Expr e, FieldLike f, Expr src, Expr q) { - exists(FieldLikeAccess fa, AssignableDefinition def | +private predicate fieldOrPropertyAssign(Expr e, Content c, Expr src, Expr q) { + exists(FieldOrPropertyAccess fa, FieldOrProperty f, AssignableDefinition def | def.getTargetAccess() = fa and - f = fa.getTarget().getSourceDeclaration() and - not f.isStatic() and + f = fa.getTarget() and + c = f.getContent() and src = def.getSource() and q = fa.getQualifier() and e = def.getExpr() + | + f.isFieldLike() and + f instanceof InstanceFieldOrProperty + or + exists(AccessPath ap | + LibraryFlow::libraryFlow(_, _, ap, _, _, _) and + ap.contains(f.getContent()) + ) ) } /** - * Holds if `oc` has an object initializer that assigns `src` to non-static field or - * field-like property `f`. + * Holds if `oc` has an object initializer that assigns `src` to field or + * property `c`. */ -private predicate instanceFieldLikeInit(ObjectCreation oc, FieldLike f, Expr src) { - exists(MemberInitializer mi | +private predicate fieldOrPropertyInit(ObjectCreation oc, Content c, Expr src) { + exists(MemberInitializer mi, FieldOrProperty f | mi = oc.getInitializer().(ObjectInitializer).getAMemberInitializer() and - f = mi.getInitializedMember().getSourceDeclaration() and - not f.isStatic() and + f = mi.getInitializedMember() and + c = f.getContent() and src = mi.getRValue() + | + f.isFieldLike() and + f instanceof InstanceFieldOrProperty + or + exists(AccessPath ap | + LibraryFlow::libraryFlow(_, _, ap, _, _, _) and + ap.contains(f.getContent()) + ) ) } -private Type getCSharpType(DotNet::Type t) { +/** Holds if property `p1` overrides or implements source declaration property `p2`. */ +private predicate overridesOrImplementsSourceDecl(Property p1, Property p2) { + p1.getOverridee*().getSourceDeclaration() = p2 + or + p1.getAnUltimateImplementee().getSourceDeclaration() = p2 +} + +/** + * Holds if `e2` is an expression that reads field or property `c` from + * expresion `e1`. This takes overriding into account for properties written + * from library code. + */ +private predicate fieldOrPropertyRead(Expr e1, Content c, FieldOrPropertyRead e2) { + e1 = e2.getQualifier() and + exists(FieldOrProperty ret | c = ret.getContent() | + ret.isFieldLike() and + ret = e2.getTarget() + or + exists(AccessPath ap, Property target | + LibraryFlow::libraryFlow(_, _, _, _, ap, _) and + ap.contains(ret.getContent()) and + target.getGetter() = e2.(PropertyCall).getARuntimeTarget() and + overridesOrImplementsSourceDecl(target, ret) + ) + ) +} + +Type getCSharpType(DotNet::Type t) { result = t or result.matchesHandle(t) @@ -359,8 +372,7 @@ private module Cached { TSsaDefinitionNode(Ssa::Definition def) or TInstanceParameterNode(Callable c) { c.hasBody() and not c.(Modifiable).isStatic() } or TCilParameterNode(CIL::Parameter p) { p.getMethod().hasBody() } or - TTaintedParameterNode(Parameter p) { explicitParameterNode(_, p) } or - TTaintedReturnNode(ControlFlow::Nodes::ElementNode cfn) { + TYieldReturnNode(ControlFlow::Nodes::ElementNode cfn) { any(Callable c).canYieldReturn(cfn.getElement()) } or TImplicitCapturedArgumentNode(ControlFlow::Nodes::ElementNode cfn, LocalScopeVariable v) { @@ -374,6 +386,14 @@ private module Cached { cfn.getElement() instanceof DelegateArgumentToLibraryCallable and any(DelegateArgumentConfiguration x).hasExprPath(_, cfn, _, call) } or + TImplicitDelegateArgumentNode(ControlFlow::Nodes::ElementNode cfn, int i, int j) { + exists(Call call, CallableFlowSinkDelegateArg sink | + LibraryFlow::libraryFlow(call, _, _, sink, _, _) and + i = sink.getDelegateIndex() and + j = sink.getDelegateParameterIndex() and + call.getArgument(i).getAControlFlowNode() = cfn + ) + } or TMallocNode(ControlFlow::Nodes::ElementNode cfn) { cfn.getElement() instanceof ObjectCreation } or TExprPostUpdateNode(ControlFlow::Nodes::ElementNode cfn) { exists(Argument a, Type t | @@ -386,13 +406,19 @@ private module Cached { t = any(TypeParameter tp | not tp.isValueType()) ) or - instanceFieldLikeAssign(_, _, _, cfn.getElement()) + fieldOrPropertyAssign(_, _, _, cfn.getElement()) or - exists(TExprPostUpdateNode upd, FieldLikeAccess fla | + exists(TExprPostUpdateNode upd, FieldOrPropertyAccess fla | upd = TExprPostUpdateNode(fla.getAControlFlowNode()) | cfn.getElement() = fla.getQualifier() ) + } or + TLibraryCodeNode( + ControlFlow::Node callCfn, CallableFlowSource source, AccessPath sourceAp, + CallableFlowSink sink, AccessPath sinkAp, boolean preservesValue + ) { + LibraryFlow::libraryFlow(callCfn.getElement(), source, sourceAp, sink, sinkAp, preservesValue) } /** @@ -415,11 +441,15 @@ private module Cached { or LocalFlow::localFlowCapturedVarStep(nodeFrom, nodeTo) or - flowOutOfDelegateLibraryCall(nodeFrom, nodeTo, true) - or - flowThroughLibraryCallableOutRef(_, nodeFrom, nodeTo, true) - or LocalFlow::localFlowStepCil(nodeFrom, nodeTo) + or + exists(LibraryCodeNode n | n.preservesValue() | + n = nodeTo and + nodeFrom = n.getPredecessor(AccessPath::empty()) + or + n = nodeFrom and + nodeTo = n.getSuccessor(AccessPath::empty()) + ) } /** @@ -446,25 +476,26 @@ private module Cached { cached newtype TContent = - TFieldLikeContent(FieldLike f) { not f.isStatic() and f.getSourceDeclaration() = f } + TFieldContent(Field f) { f = f.getSourceDeclaration() } or + TPropertyContent(Property p) { p = p.getSourceDeclaration() } /** * Holds if data can flow from `node1` to `node2` via an assignment to * content `c`. */ cached - predicate storeStepImpl(ExprNode node1, Content c, PostUpdateNode node2) { - exists(StoreStepConfiguration x, Node preNode2 | - preNode2 = node2.getPreUpdateNode() and + predicate storeStepImpl(Node node1, Content c, Node node2) { + exists(StoreStepConfiguration x, ExprNode preNode2 | + preNode2 = node2.(PostUpdateNode).getPreUpdateNode() and x.hasNodePath(node1, preNode2) and - instanceFieldLikeAssign(_, c.(FieldLikeContent).getField(), node1.asExpr(), preNode2.asExpr()) + fieldOrPropertyAssign(_, c, node1.asExpr(), preNode2.getExpr()) ) or - exists(StoreStepConfiguration x | - x.hasNodePath(node1, node2) and - instanceFieldLikeInit(node2.(ObjectCreationNode).getExpr(), c.(FieldLikeContent).getField(), - node1.asExpr()) + exists(StoreStepConfiguration x | x.hasNodePath(node1, node2) | + fieldOrPropertyInit(node2.(ObjectCreationNode).getExpr(), c, node1.asExpr()) ) + or + node2 = node1.(LibraryCodeNode).getSuccessor(any(AccessPath ap | ap.getHead() = c)) } /** @@ -474,9 +505,10 @@ private module Cached { predicate readStepImpl(Node node1, Content c, Node node2) { exists(ReadStepConfiguration x | x.hasNodePath(node1, node2) and - c.(FieldLikeContent).getField() = - node2.asExpr().(FieldLikeRead).getTarget().getSourceDeclaration() + fieldOrPropertyRead(node1.asExpr(), c, node2.asExpr()) ) + or + node1 = node2.(LibraryCodeNode).getPredecessor(any(AccessPath ap | ap.getHead() = c)) } /** @@ -495,19 +527,6 @@ private module Cached { ) } - /** - * Gets a representative type for `t` for the purpose of pruning possible flow. - */ - cached - DataFlowType getErasedRepr(DotNet::Type t) { - exists(Type t0 | result = Gvn::getGlobalValueNumber(t0) | - t0 = getCSharpType(t) - or - not exists(getCSharpType(t)) and - t0 instanceof ObjectType - ) - } - /** * Holds if GVNs `t1` and `t2` may have a common sub type. Neither `t1` nor * `t2` are allowed to be type parameters. @@ -607,44 +626,6 @@ private module ParameterNodes { override string toString() { result = "this" } } - /** - * A tainted parameter. Tainted parameters are a mere implementation detail, used - * to restrict tainted flow into callables to just taint tracking (just like flow - * out of `TaintedReturnNode`s is restricted to taint tracking). - */ - class TaintedParameterNode extends ParameterNode, TTaintedParameterNode { - private Parameter parameter; - - TaintedParameterNode() { this = TTaintedParameterNode(parameter) } - - /** Gets the underlying parameter node. */ - ExplicitParameterNode getUnderlyingNode() { explicitParameterNode(result, parameter) } - - // `getParameter()` is explicitly *not* overriden to return `parameter`, - // as that would otherwise enable tainted parameters to accidentally be - // used by users of the library - override predicate isParameterOf(DataFlowCallable c, int i) { - c = parameter.getCallable() and - // we model tainted parameters as if they had been extra parameters after - // the actual parameters - i = parameter.getPosition() + c.getNumberOfParameters() - } - - override Callable getEnclosingCallable() { - result = this.getUnderlyingNode().getEnclosingCallable() - } - - override Type getType() { - // Taint tracking steps are allowed to change the type of the tracked object, - // so `result = this.getUnderlyingNode().getType()` is too restrictive - result instanceof ObjectType - } - - override Location getLocation() { result = this.getUnderlyingNode().getLocation() } - - override string toString() { result = this.getUnderlyingNode().toString() } - } - module ImplicitCapturedParameterNodeImpl { /** An implicit entry definition for a captured variable. */ class SsaCapturedEntryDefinition extends Ssa::ImplicitEntryDefinition { @@ -688,7 +669,7 @@ private module ParameterNodes { * An implicit parameter is added in order to be able to track flow into * capturing callables, as if an explicit `ref` parameter had been used: * - * ``` + * ```csharp * void M() { void M() { * int i = 0; int i = 0; * void In() { => void In(ref int i0) { // implicit i0 parameter @@ -741,47 +722,6 @@ private module ArgumentNodes { } } - /** - * Holds if `arg` is an argument of a call, which resolves to a library callable - * that is known to forward `arg` into the `i`th parameter of a supplied - * delegate `delegate`. - * - * For example, in - * - * ``` - * x.Select(Foo); - * ``` - * - * `arg = x`, `i = 0`, `call = x.Select(Foo)`, and `delegate = Foo`. - */ - private predicate flowIntoCallableLibraryCall( - ExplicitArgumentNode arg, ImplicitDelegateDataFlowCall delegate, int i - ) { - exists(DataFlowCall call, int j, boolean preservesValue | - preservesValue = true and i = j - or - preservesValue = false and i = j + delegate.getNumberOfDelegateParameters() - | - exists(DelegateArgumentConfiguration x, Call callExpr, ExprNode argExpr | - x - .hasExprPath(argExpr.getExpr(), argExpr.getControlFlowNode(), callExpr, - call.getControlFlowNode()) - | - exists(int k | - libraryFlowDelegateCallIn(callExpr, _, argExpr.getExpr(), preservesValue, j, k) and - arg = argExpr and - delegate.isArgumentOf(call, k) - ) - or - exists(int k, int l | libraryFlowDelegateCallOutIn(callExpr, _, preservesValue, k, j, l) | - delegate.isArgumentOf(call, l) and - arg.(ImplicitDelegateOutNode).isArgumentOf(call, k) and - arg = TImplicitDelegateOutNode(argExpr.getControlFlowNode(), _) - ) - ) - ) - } - private class ArgumentConfiguration extends ControlFlowReachabilityConfiguration { ArgumentConfiguration() { this = "ArgumentConfiguration" } @@ -801,10 +741,6 @@ private module ArgumentNodes { this.asExpr() instanceof Argument or this.asExpr() = any(CIL::Call call).getAnArgument() - or - libraryFlowDelegateCallIn(_, _, this.asExpr(), _, _, _) - or - this.(ImplicitDelegateOutNode).isArgumentOf(_, _) } override predicate argumentOf(DataFlowCall call, int pos) { @@ -821,8 +757,6 @@ private module ArgumentNodes { c = call.getExpr() and arg = c.getArgument(pos) ) - or - flowIntoCallableLibraryCall(this, call, pos) } } @@ -833,7 +767,7 @@ private module ArgumentNodes { * An implicit node is added in order to be able to track flow into capturing * callables, as if an explicit parameter had been used: * - * ``` + * ```csharp * void M() { void M() { * int i = 0; int i = 0; * void Out() { i = 1; } => void Out(ref int i0) { i0 = 1; } @@ -913,6 +847,39 @@ private module ArgumentNodes { override string toString() { result = "malloc" } } + + /** + * A data flow node that represents an implicit argument of an implicit delegate + * call in library code. For example, in + * + * ```csharp + * x.Select(Foo); + * ``` + * + * `x` is an implicit argument of the implicit call to `Foo`. + */ + class ImplicitDelegateArgumentNode extends ArgumentNode, TImplicitDelegateArgumentNode { + private ControlFlow::Node cfn; + private int i; + private int j; + + ImplicitDelegateArgumentNode() { this = TImplicitDelegateArgumentNode(cfn, i, j) } + + private ImplicitDelegateDataFlowCall getDelegateCall() { result.getControlFlowNode() = cfn } + + override predicate argumentOf(DataFlowCall call, int pos) { + call = this.getDelegateCall() and + pos = j + } + + override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() } + + override Type getType() { result = this.getDelegateCall().getDelegateParameterType(j) } + + override Location getLocation() { result = cfn.getLocation() } + + override string toString() { result = "[implicit argument " + j + "] " + cfn } + } } import ArgumentNodes @@ -964,31 +931,29 @@ private module ReturnNodes { } /** - * A tainted return node. Tainted return nodes are a mere implementation detail, - * used to restrict tainted flow out of callables to just taint tracking (just - * like flow in to `TaintedReturnParameter`s is restricted to taint tracking). + * A `yield return` node. A node is synthesized in order to be able to model + * `yield return`s as stores into collections, i.e., there is flow from `e` + * to `yield return e [e]`. */ - class TaintedReturnNode extends ReturnNode, TTaintedReturnNode { + class YieldReturnNode extends ReturnNode, PostUpdateNode, TYieldReturnNode { private ControlFlow::Nodes::ElementNode cfn; + private YieldReturnStmt yrs; - TaintedReturnNode() { this = TTaintedReturnNode(cfn) } + YieldReturnNode() { this = TYieldReturnNode(cfn) and yrs.getExpr().getAControlFlowNode() = cfn } - /** Gets the underlying return node. */ - ExprReturnNode getUnderlyingNode() { result.getControlFlowNode() = cfn } + YieldReturnStmt getYieldReturnStmt() { result = yrs } override YieldReturnKind getKind() { any() } - override Callable getEnclosingCallable() { - result = this.getUnderlyingNode().getEnclosingCallable() - } + override ExprNode getPreUpdateNode() { result.getControlFlowNode() = cfn } - override Type getType() { - result = this.getUnderlyingNode().getEnclosingCallable().getReturnType() - } + override Callable getEnclosingCallable() { result = yrs.getEnclosingCallable() } - override Location getLocation() { result = this.getUnderlyingNode().getLocation() } + override Type getType() { result = yrs.getEnclosingCallable().getReturnType() } - override string toString() { result = this.getUnderlyingNode().toString() } + override Location getLocation() { result = yrs.getLocation() } + + override string toString() { result = yrs.toString() } } /** @@ -998,7 +963,7 @@ private module ReturnNodes { * An implicit node is added in order to be able to track flow out of capturing * callables, as if an explicit `ref` parameter had been used: * - * ``` + * ```csharp * void M() { void M() { * int i = 0; int i = 0; * void Out() { void Out(ref int i0) { @@ -1188,68 +1153,273 @@ private module OutNodes { import OutNodes -private class FlowThroughLibraryCallableOutRefConfiguration extends ControlFlowReachabilityConfiguration { - FlowThroughLibraryCallableOutRefConfiguration() { - this = "FlowThroughLibraryCallableOutRefConfiguration" - } - - override predicate candidateDef( - Expr e, AssignableDefinition def, ControlFlowElement scope, boolean exactScope, - boolean isSuccessor +/** + * Provides predicates related to flow through library code, based on + * the flow summaries in `LibraryTypeDataFlow.qll`. + */ +module LibraryFlow { + pragma[nomagic] + private ValueOrRefType getPreciseSourceProperty0( + Call call, CallableFlowSource source, AccessPath sourceAp, Property p ) { - exists(MethodCall mc, Parameter outRef | libraryFlowOutRef(mc, e, outRef, _) | - def.getTargetAccess() = mc.getArgumentForParameter(outRef) and - def instanceof AssignableDefinitions::OutRefDefinition and - scope = mc and - isSuccessor = true and - exactScope = false + exists(LibraryTypeDataFlow ltdf, Property p0 | + ltdf.callableFlow(source, sourceAp, _, _, call.getTarget().getSourceDeclaration()) and + sourceAp = AccessPath::property(p0) and + overridesOrImplementsSourceDecl(p, p0) and + result = source.getSourceType(call) ) } + + /** + * Gets a precise source property for source `source` and access path `sourceAp`, + * in the context of `call`. For example, in + * + * ```csharp + * var list = new List(); + * var count = list.Count(); + * ``` + * + * the step from `list` to `list.Count()`, which may be modeled as a read of + * the `Count` property from `ICollection`, can be strengthened to be a + * read of the `Count` property from `List`. + */ + pragma[nomagic] + private Property getPreciseSourceProperty( + Call call, CallableFlowSource source, AccessPath sourceAp + ) { + getPreciseSourceProperty0(call, source, sourceAp, result).hasMember(result) + } + + pragma[nomagic] + private ValueOrRefType getPreciseSinkProperty0( + Call call, CallableFlowSink sink, AccessPath sinkAp, Property p + ) { + exists(LibraryTypeDataFlow ltdf, Property p0 | + ltdf.callableFlow(_, _, sink, sinkAp, call.getTarget().getSourceDeclaration()) and + sinkAp = AccessPath::property(p0) and + overridesOrImplementsSourceDecl(p, p0) and + result = sink.getSinkType(call) + ) + } + + /** + * Gets a precise sink property for sink `sink` and access path `sinkAp`, + * in the context of `call`. For example, in + * + * ```csharp + * var list = new List(); + * list.Add("taint"); + * var enumerator = list.getEnumerator(); + * ``` + * + * the step from `list` to `list.getEnumerator()`, which may be modeled as a + * read of a collection element followed by a store into the `Current` + * property, can be strengthened to be a store into the `Current` property + * from `List.Enumerator`, rather than the generic `Current` property + * from `IEnumerator`. + */ + pragma[nomagic] + private Property getPreciseSinkProperty(Call call, CallableFlowSink sink, AccessPath sinkAp) { + getPreciseSinkProperty0(call, sink, sinkAp, result).hasMember(result) + } + + /** + * Holds if data can flow from a node of kind `source` to a node of kind `sink`, + * using a call to a library callable. + * + * `sourceAp` describes the contents of the source node that flows to the sink + * (if any), and `sinkAp` describes the contents of the sink that it flows to + * (if any). + * + * `preservesValue = false` implies that both `sourceAp` and `sinkAp` are empty. + */ + pragma[nomagic] + predicate libraryFlow( + Call call, CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, + AccessPath sinkAp, boolean preservesValue + ) { + exists(LibraryTypeDataFlow ltdf, SourceDeclarationCallable c | + c = call.getTarget().getSourceDeclaration() + | + ltdf.callableFlow(source, sink, c, preservesValue) and + sourceAp = AccessPath::empty() and + sinkAp = AccessPath::empty() + or + preservesValue = true and + exists(AccessPath sourceAp0, AccessPath sinkAp0 | + ltdf.callableFlow(source, sourceAp0, sink, sinkAp0, c) and + ( + not sourceAp0 = AccessPath::property(_) and + sourceAp = sourceAp0 + or + exists(Property p | + overridesOrImplementsSourceDecl(p, + getPreciseSourceProperty(call, source, sourceAp0).getSourceDeclaration()) and + sourceAp = AccessPath::property(p) + ) + ) and + ( + not sinkAp0 = AccessPath::property(_) and + sinkAp = sinkAp0 + or + sinkAp = AccessPath::property(getPreciseSinkProperty(call, sink, sinkAp0)) + ) + ) + ) + } + + class LibrarySourceConfiguration extends ControlFlowReachabilityConfiguration { + LibrarySourceConfiguration() { this = "LibrarySourceConfiguration" } + + override predicate candidate( + Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor + ) { + exists(CallableFlowSource source | + libraryFlow(e2, source, _, _, _, _) and + e1 = source.getSource(e2) and + scope = e2 and + exactScope = false and + isSuccessor = true + ) + } + } + + class LibrarySinkConfiguration extends ControlFlowReachabilityConfiguration { + LibrarySinkConfiguration() { this = "LibrarySinkConfiguration" } + + override predicate candidate( + Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor + ) { + exists(CallableFlowSink sink | + libraryFlow(e1, _, _, sink, _, _) and + e2 = sink.getSink(e1) and + scope = e1 and + exactScope = false and + isSuccessor = false + ) + } + + override predicate candidateDef( + Expr e, AssignableDefinition def, ControlFlowElement scope, boolean exactScope, + boolean isSuccessor + ) { + exists(CallableFlowSinkArg sink | + libraryFlow(e, _, _, sink, _, _) and + scope = e and + exactScope = false and + isSuccessor = true and + def.getTargetAccess() = sink.getArgument(e) and + def instanceof AssignableDefinitions::OutRefDefinition + ) + } + } } -/** - * Holds if `arg` is an argument of the method call `mc`, where the target - * of `mc` is a library callable that forwards `arg` to an `out`/`ref` argument - * `node`. Example: - * - * ``` - * int i; - * Int32.TryParse("42", out i); - * ``` - * - * `mc = Int32.TryParse("42", out i)`, `arg = "42"`, and `node` is the access - * to `i` in `out i`. - */ -predicate flowThroughLibraryCallableOutRef( - MethodCall mc, ExprNode arg, SsaDefinitionNode node, boolean preservesValue -) { - libraryFlowOutRef(mc, arg.getExpr(), _, preservesValue) and - any(FlowThroughLibraryCallableOutRefConfiguration x).hasNodePath(arg, node) +/** A data-flow node used to model flow through library code. */ +class LibraryCodeNode extends Node, TLibraryCodeNode { + private ControlFlow::Node callCfn; + private CallableFlowSource source; + private AccessPath sourceAp; + private CallableFlowSink sink; + private AccessPath sinkAp; + private boolean preservesValue; + + LibraryCodeNode() { + this = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue) + } + + /** Holds if this node is part of a value-preserving library step. */ + predicate preservesValue() { preservesValue = true } + + /** + * Gets the predecessor of this library-code node. `ap` describes the content + * that is read from when entering this node (if any). + */ + Node getPredecessor(AccessPath ap) { + ap = sourceAp and + ( + exists(LibraryFlow::LibrarySourceConfiguration x, Call call | + callCfn = call.getAControlFlowNode() and + x.hasExprPath(source.getSource(call), result.(ExprNode).getControlFlowNode(), _, callCfn) + ) + or + exists(DataFlowCall call, int pos | + pos = source.(CallableFlowSourceDelegateArg).getArgumentIndex() and + result.(ImplicitDelegateOutNode).isArgumentOf(call, pos) and + callCfn = call.getControlFlowNode() + ) + ) + } + + /** + * Gets the successor of this library-code node. `ap` describes the content that + * is stored into when leaving this node (if any). + */ + Node getSuccessor(AccessPath ap) { + ap = sinkAp and + ( + exists(LibraryFlow::LibrarySinkConfiguration x, Call call, ExprNode e | + callCfn = call.getAControlFlowNode() and + x.hasExprPath(_, callCfn, sink.getSink(call), e.getControlFlowNode()) + | + sink instanceof CallableFlowSinkReturn and + result = e + or + sink instanceof CallableFlowSinkQualifier and + if sinkAp = AccessPath::empty() + then result = e + else result.(ExprPostUpdateNode).getPreUpdateNode() = e + ) + or + exists(LibraryFlow::LibrarySinkConfiguration x, OutRefReturnKind k | + result = + any(ParamOutNode out | + out.getCall(k).getControlFlowNode() = callCfn and + sink.(CallableFlowSinkArg).getArgumentIndex() = k.getPosition() and + x.hasDefPath(_, callCfn, out.getDefinition(), _) + ) + ) + or + exists(DataFlowCall call, ImplicitDelegateDataFlowCall dcall, int i, int j | + sink = + any(CallableFlowSinkDelegateArg s | + i = s.getDelegateIndex() and j = s.getDelegateParameterIndex() + ) and + result = TImplicitDelegateArgumentNode(dcall.getControlFlowNode(), _, j) and + dcall.isArgumentOf(call, i) and + callCfn = call.getControlFlowNode() + ) + ) + } + + override Callable getEnclosingCallable() { result = callCfn.getEnclosingCallable() } + + override DataFlowType getTypeBound() { + preservesValue = true and + sourceAp = AccessPath::empty() and + result = this.getPredecessor(_).getTypeBound() + or + result = sourceAp.getHead().getType() + or + preservesValue = false and + result = this.getSuccessor(_).getTypeBound() + } + + override Location getLocation() { result = callCfn.getLocation() } + + override string toString() { result = "[library code] " + callCfn } } -/** - * Holds if the output from the delegate `delegate` flows to `out`. The delegate - * is passed as an argument to a library callable, which invokes the delegate. - * Example: - * - * ``` - * x.Select(Foo); - * ``` - * - * `delegate = Foo`, `out = x.Select(Foo)`, and `preservesValue = false`. - */ -predicate flowOutOfDelegateLibraryCall( - ImplicitDelegateOutNode delegate, ExprOutNode out, boolean preservesValue -) { - exists(DataFlowCall call, int i | - libraryFlowDelegateCallOut(call.getExpr(), _, out.getExpr(), preservesValue, i) and - delegate.isArgumentOf(call, i) and - out.getControlFlowNode() = call.getControlFlowNode() - ) -} +/** A field or a property. */ +private class FieldOrProperty extends Assignable, Modifiable { + FieldOrProperty() { + this instanceof Field + or + this instanceof Property + } -private class FieldLike extends Assignable, Modifiable { - FieldLike() { + /** Holds if this is either a field or a field-like property. */ + predicate isFieldLike() { this instanceof Field or this = any(Property p | @@ -1261,42 +1431,54 @@ private class FieldLike extends Assignable, Modifiable { ) ) } + + /** Gets the content that matches this field or property. */ + Content getContent() { + result.(FieldContent).getField() = this.getSourceDeclaration() + or + result.(PropertyContent).getProperty() = this.getSourceDeclaration() + } } -private class FieldLikeAccess extends AssignableAccess, QualifiableExpr { - FieldLikeAccess() { this.getTarget() instanceof FieldLike } +private class InstanceFieldOrProperty extends FieldOrProperty { + InstanceFieldOrProperty() { not this.isStatic() } } -private class FieldLikeRead extends FieldLikeAccess, AssignableRead { } +private class FieldOrPropertyAccess extends AssignableAccess, QualifiableExpr { + FieldOrPropertyAccess() { this.getTarget() instanceof FieldOrProperty } +} -/** - * Holds if the field-like read `flr` is not completely determined by explicit - * SSA updates. - */ -private predicate hasNonlocalValue(FieldLikeRead flr) { - flr = any(Ssa::ImplicitUntrackedDefinition udef).getARead() - or - exists(Ssa::Definition def, Ssa::ImplicitDefinition idef | - def.getARead() = flr and - idef = def.getAnUltimateDefinition() - | - idef instanceof Ssa::ImplicitEntryDefinition or - idef instanceof Ssa::ImplicitCallDefinition - ) +private class FieldOrPropertyRead extends FieldOrPropertyAccess, AssignableRead { + /** + * Holds if this field-like read is not completely determined by explicit + * SSA updates. + */ + predicate hasNonlocalValue() { + this = any(Ssa::ImplicitUntrackedDefinition udef).getARead() + or + exists(Ssa::Definition def, Ssa::ImplicitDefinition idef | + def.getARead() = this and + idef = def.getAnUltimateDefinition() + | + idef instanceof Ssa::ImplicitEntryDefinition or + idef instanceof Ssa::ImplicitCallDefinition + ) + } } /** A write to a static field/property. */ private class StaticFieldLikeJumpNode extends NonLocalJumpNode, ExprNode { - FieldLike fl; - FieldLikeRead flr; + FieldOrProperty fl; + FieldOrPropertyRead flr; ExprNode succ; StaticFieldLikeJumpNode() { fl.isStatic() and + fl.isFieldLike() and fl.getAnAssignedValue() = this.getExpr() and fl.getAnAccess() = flr and flr = succ.getExpr() and - hasNonlocalValue(flr) + flr.hasNonlocalValue() } override ExprNode getAJumpSuccessor(boolean preservesValue) { @@ -1306,41 +1488,6 @@ private class StaticFieldLikeJumpNode extends NonLocalJumpNode, ExprNode { predicate jumpStep = jumpStepImpl/2; -/** - * A reference contained in an object. Currently limited to instance fields - * and field-like instance properties. - */ -class Content extends TContent { - /** Gets a textual representation of this content. */ - abstract string toString(); - - abstract Location getLocation(); - - /** Gets the type of the object containing this content. */ - abstract DataFlowType getContainerType(); - - /** Gets the type of this content. */ - abstract DataFlowType getType(); -} - -private class FieldLikeContent extends Content, TFieldLikeContent { - private FieldLike f; - - FieldLikeContent() { this = TFieldLikeContent(f) } - - FieldLike getField() { result = f } - - override string toString() { result = f.toString() } - - override Location getLocation() { result = f.getLocation() } - - override DataFlowType getContainerType() { - result = Gvn::getGlobalValueNumber(f.getDeclaringType()) - } - - override DataFlowType getType() { result = Gvn::getGlobalValueNumber(f.getType()) } -} - private class StoreStepConfiguration extends ControlFlowReachabilityConfiguration { StoreStepConfiguration() { this = "StoreStepConfiguration" } @@ -1349,11 +1496,11 @@ private class StoreStepConfiguration extends ControlFlowReachabilityConfiguratio ) { exactScope = false and isSuccessor = false and - instanceFieldLikeAssign(scope, _, e1, e2) + fieldOrPropertyAssign(scope, _, e1, e2) or exactScope = false and isSuccessor = false and - instanceFieldLikeInit(e2, _, e1) and + fieldOrPropertyInit(e2, _, e1) and scope = e2 } } @@ -1368,7 +1515,7 @@ private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration ) { exactScope = false and isSuccessor = true and - e1 = e2.(FieldLikeRead).getQualifier() and + fieldOrPropertyRead(e1, _, e2) and scope = e2 } } @@ -1432,7 +1579,7 @@ private module PostUpdateNodes { override MallocNode getPreUpdateNode() { this = TExprNode(result.getControlFlowNode()) } } - private class ExprPostUpdateNode extends PostUpdateNode, TExprPostUpdateNode { + class ExprPostUpdateNode extends PostUpdateNode, TExprPostUpdateNode { private ControlFlow::Nodes::ElementNode cfn; ExprPostUpdateNode() { this = TExprPostUpdateNode(cfn) } @@ -1508,3 +1655,6 @@ int accessPathLimit() { result = 3 } * This predicate is only used for consistency checks. */ predicate isImmutableOrUnobservable(Node n) { none() } + +pragma[inline] +DataFlowType getErasedRepr(DataFlowType t) { result = t } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll index d5dff3b8b21..328db073d6e 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll @@ -5,6 +5,7 @@ private import DataFlowDispatch private import DataFlowPrivate private import semmle.code.csharp.Caching private import semmle.code.csharp.controlflow.Guards +private import semmle.code.csharp.Unification /** * An element, viewed as a node in a data flow graph. Either an expression @@ -40,8 +41,17 @@ class Node extends TNode { cached DotNet::Type getType() { none() } - /** Gets an upper bound on the type of this node. */ - DotNet::Type getTypeBound() { result = this.getType() } // stub implementation + /** INTERNAL: Do not use. Gets an upper bound on the type of this node. */ + cached + DataFlowType getTypeBound() { + Stages::DataFlowStage::forceCachingInSameStage() and + exists(Type t0 | result = Gvn::getGlobalValueNumber(t0) | + t0 = getCSharpType(this.getType()) + or + not exists(getCSharpType(this.getType())) and + t0 instanceof ObjectType + ) + } /** Gets the enclosing callable of this node. */ cached @@ -136,8 +146,7 @@ class ParameterNode extends Node { this.(SsaDefinitionNode).getDefinition() instanceof ImplicitCapturedParameterNodeImpl::SsaCapturedEntryDefinition or this = TInstanceParameterNode(_) or - this = TCilParameterNode(_) or - this = TTaintedParameterNode(_) + this = TCilParameterNode(_) } /** Gets the parameter corresponding to this node, if any. */ @@ -231,3 +240,60 @@ class BarrierGuard extends Guard { ) } } + +/** + * A reference contained in an object. This is either a field or a property. + */ +class Content extends TContent { + /** Gets a textual representation of this content. */ + string toString() { none() } + + /** Gets the location of this content. */ + Location getLocation() { none() } + + /** Gets the type of the object containing this content. */ + DataFlowType getContainerType() { none() } + + /** Gets the type of this content. */ + DataFlowType getType() { none() } +} + +/** A reference to a field. */ +class FieldContent extends Content, TFieldContent { + private Field f; + + FieldContent() { this = TFieldContent(f) } + + /** Gets the field that is referenced. */ + Field getField() { result = f } + + override string toString() { result = f.toString() } + + override Location getLocation() { result = f.getLocation() } + + override DataFlowType getContainerType() { + result = Gvn::getGlobalValueNumber(f.getDeclaringType()) + } + + override DataFlowType getType() { result = Gvn::getGlobalValueNumber(f.getType()) } +} + +/** A reference to a property. */ +class PropertyContent extends Content, TPropertyContent { + private Property p; + + PropertyContent() { this = TPropertyContent(p) } + + /** Gets the property that is referenced. */ + Property getProperty() { result = p } + + override string toString() { result = p.toString() } + + override Location getLocation() { result = p.getLocation() } + + override DataFlowType getContainerType() { + result = Gvn::getGlobalValueNumber(p.getDeclaringType()) + } + + override DataFlowType getType() { result = Gvn::getGlobalValueNumber(p.getType()) } +} diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll index 9c41d5b1e3e..e0230c4f1d6 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll @@ -118,6 +118,9 @@ library class DelegateArgumentToLibraryCallable extends Expr { /** Gets the call that this argument belongs to. */ Call getCall() { result = call } + /** Gets the index of this delegate argument in the call. */ + int getArgumentIndex() { this.getCall().getArgument(result) = this } + /** Gets the delegate type of this argument. */ DelegateType getDelegateType() { result = dt } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll index 70047de7433..93fe29c4619 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll @@ -45,9 +45,6 @@ private class LocalTaintExprStepConfiguration extends ControlFlowReachabilityCon ) { exactScope = false and ( - // Taint propagation using library code - LocalFlow::libraryFlow(e1, e2, scope, isSuccessor, false) - or // Taint from assigned value to element qualifier (`x[i] = 0`) exists(AssignExpr ae | e1 = ae.getRValue() and @@ -162,11 +159,7 @@ module Cached { Stages::DataFlowStage::forceCachingInSameStage() and any(LocalTaintExprStepConfiguration x).hasNodePath(nodeFrom, nodeTo) or - nodeTo = nodeFrom.(TaintedParameterNode).getUnderlyingNode() - or - nodeFrom = nodeTo.(TaintedReturnNode).getUnderlyingNode() - or - flowOutOfDelegateLibraryCall(nodeFrom, nodeTo, false) + nodeFrom = nodeTo.(YieldReturnNode).getPreUpdateNode() or localTaintStepCil(nodeFrom, nodeTo) or @@ -180,7 +173,13 @@ module Cached { access.(PropertyRead).getQualifier() = nodeFrom.asExpr() ) or - flowThroughLibraryCallableOutRef(_, nodeFrom, nodeTo, false) + exists(LibraryCodeNode n | not n.preservesValue() | + n = nodeTo and + nodeFrom = n.getPredecessor(AccessPath::empty()) + or + n = nodeFrom and + nodeTo = n.getSuccessor(AccessPath::empty()) + ) } } diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Access.qll b/csharp/ql/src/semmle/code/csharp/exprs/Access.qll index d1e1017e0d1..842c374ecd1 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Access.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Access.qll @@ -566,10 +566,10 @@ class IndexerAccess extends AssignableMemberAccess, ElementAccess, IndexerAccess * } * ``` */ -class IndexerRead extends IndexerAccess, AssignableRead { - override IndexerRead getANextRead() { result = AssignableRead.super.getANextRead() } +class IndexerRead extends IndexerAccess, ElementRead { + override IndexerRead getANextRead() { result = ElementRead.super.getANextRead() } - override IndexerRead getAReachableRead() { result = AssignableRead.super.getAReachableRead() } + override IndexerRead getAReachableRead() { result = ElementRead.super.getAReachableRead() } } /** @@ -586,7 +586,7 @@ class IndexerRead extends IndexerAccess, AssignableRead { * } * ``` */ -class IndexerWrite extends IndexerAccess, AssignableWrite { } +class IndexerWrite extends IndexerAccess, ElementWrite { } /** * An access to a virtual indexer - an indexer that is virtual or defined in @@ -818,7 +818,7 @@ class ArrayAccess extends ElementAccess, @array_access_expr { * } * ``` */ -class ArrayRead extends ArrayAccess, AssignableRead { } +class ArrayRead extends ArrayAccess, ElementRead { } /** * An access to an array that updates the underlying value, for example @@ -830,7 +830,7 @@ class ArrayRead extends ArrayAccess, AssignableRead { } * } * ``` */ -class ArrayWrite extends ArrayAccess, AssignableWrite { } +class ArrayWrite extends ArrayAccess, ElementWrite { } /** * An access to a namespace, for example `System` in `nameof(System)`. diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll b/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll index 68dfc910911..b439f958a01 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll @@ -3,7 +3,7 @@ */ import csharp -import semmle.code.csharp.dataflow.LibraryTypeDataFlow +private import semmle.code.csharp.dataflow.LibraryTypeDataFlow /** Definitions relating to the `Json.NET` package. */ module JsonNET { diff --git a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected index 3aa1d59c012..cad303fa914 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected @@ -7,18 +7,15 @@ | CSharp7.cs:17:9:17:11 | this | CSharp7.cs:17:18:17:22 | this access | | CSharp7.cs:21:9:21:11 | this | CSharp7.cs:21:16:21:20 | this access | | CSharp7.cs:22:9:22:11 | this | CSharp7.cs:22:16:22:20 | this access | -| CSharp7.cs:22:9:22:11 | value | CSharp7.cs:22:9:22:11 | value | | CSharp7.cs:22:9:22:11 | value | CSharp7.cs:22:24:22:28 | access to parameter value | | CSharp7.cs:25:5:25:27 | this | CSharp7.cs:16:9:16:13 | this access | | CSharp7.cs:26:6:26:28 | this | CSharp7.cs:26:35:26:39 | this access | -| CSharp7.cs:31:19:31:19 | i | CSharp7.cs:31:19:31:19 | i | | CSharp7.cs:31:19:31:19 | i | CSharp7.cs:33:16:33:16 | access to parameter i | | CSharp7.cs:33:16:33:16 | access to parameter i | CSharp7.cs:33:16:33:20 | ... > ... | | CSharp7.cs:33:16:33:16 | access to parameter i | CSharp7.cs:33:24:33:24 | access to parameter i | | CSharp7.cs:33:24:33:24 | access to parameter i | CSharp7.cs:33:16:33:59 | ... ? ... : ... | | CSharp7.cs:33:28:33:59 | throw ... | CSharp7.cs:33:16:33:59 | ... ? ... : ... | | CSharp7.cs:41:13:41:21 | "tainted" | CSharp7.cs:41:9:41:21 | SSA def(x) | -| CSharp7.cs:44:19:44:19 | x | CSharp7.cs:44:19:44:19 | x | | CSharp7.cs:44:19:44:19 | x | CSharp7.cs:46:13:46:13 | access to parameter x | | CSharp7.cs:46:13:46:13 | access to parameter x | CSharp7.cs:46:9:46:13 | SSA def(y) | | CSharp7.cs:49:10:49:10 | this | CSharp7.cs:51:9:51:24 | this access | @@ -65,7 +62,6 @@ | CSharp7.cs:78:31:78:31 | access to local variable a | CSharp7.cs:78:27:78:32 | (..., ...) | | CSharp7.cs:79:23:79:24 | "" | CSharp7.cs:79:22:79:28 | (..., ...) | | CSharp7.cs:79:27:79:27 | access to local variable x | CSharp7.cs:79:22:79:28 | (..., ...) | -| CSharp7.cs:82:21:82:21 | x | CSharp7.cs:82:21:82:21 | x | | CSharp7.cs:82:21:82:21 | x | CSharp7.cs:84:20:84:20 | access to parameter x | | CSharp7.cs:84:16:84:24 | (..., ...) | CSharp7.cs:84:16:84:26 | access to field a | | CSharp7.cs:84:20:84:20 | access to parameter x | CSharp7.cs:84:16:84:24 | (..., ...) | @@ -116,19 +112,15 @@ | CSharp7.cs:119:19:119:20 | access to local variable m2 | CSharp7.cs:119:19:119:26 | access to field Item1 | | CSharp7.cs:123:28:123:36 | "DefUse3" | CSharp7.cs:123:22:123:36 | ... = ... | | CSharp7.cs:129:9:129:12 | this | CSharp7.cs:135:24:135:25 | this access | -| CSharp7.cs:131:20:131:20 | x | CSharp7.cs:131:20:131:20 | x | | CSharp7.cs:131:20:131:20 | x | CSharp7.cs:131:32:131:32 | access to parameter x | | CSharp7.cs:131:32:131:32 | access to parameter x | CSharp7.cs:131:32:131:36 | ... + ... | | CSharp7.cs:131:36:131:36 | 1 | CSharp7.cs:131:32:131:36 | ... + ... | -| CSharp7.cs:133:22:133:22 | t | CSharp7.cs:133:22:133:22 | t | | CSharp7.cs:133:22:133:22 | t | CSharp7.cs:133:39:133:39 | access to parameter t | | CSharp7.cs:135:24:135:25 | this access | CSharp7.cs:155:16:155:17 | this access | -| CSharp7.cs:139:29:139:29 | x | CSharp7.cs:139:29:139:29 | x | | CSharp7.cs:139:29:139:29 | x | CSharp7.cs:139:34:139:34 | access to parameter x | | CSharp7.cs:139:34:139:34 | access to parameter x | CSharp7.cs:139:34:139:38 | ... + ... | | CSharp7.cs:139:38:139:38 | 1 | CSharp7.cs:139:34:139:38 | ... + ... | | CSharp7.cs:141:9:141:51 | this | CSharp7.cs:141:38:141:39 | this access | -| CSharp7.cs:141:20:141:20 | x | CSharp7.cs:141:20:141:20 | x | | CSharp7.cs:141:20:141:20 | x | CSharp7.cs:141:26:141:26 | access to parameter x | | CSharp7.cs:141:26:141:26 | access to parameter x | CSharp7.cs:141:26:141:30 | ... > ... | | CSharp7.cs:141:26:141:26 | access to parameter x | CSharp7.cs:141:41:141:41 | access to parameter x | @@ -137,17 +129,13 @@ | CSharp7.cs:141:38:141:46 | call to local function f7 | CSharp7.cs:141:34:141:46 | ... + ... | | CSharp7.cs:141:50:141:50 | 0 | CSharp7.cs:141:26:141:50 | ... ? ... : ... | | CSharp7.cs:143:9:143:31 | this | CSharp7.cs:143:26:143:27 | this access | -| CSharp7.cs:143:20:143:20 | x | CSharp7.cs:143:20:143:20 | x | | CSharp7.cs:143:20:143:20 | x | CSharp7.cs:143:29:143:29 | access to parameter x | | CSharp7.cs:145:9:149:9 | this | CSharp7.cs:148:20:148:21 | this access | | CSharp7.cs:147:13:147:35 | this | CSharp7.cs:147:30:147:31 | this access | -| CSharp7.cs:147:24:147:24 | x | CSharp7.cs:147:24:147:24 | x | | CSharp7.cs:147:24:147:24 | x | CSharp7.cs:147:33:147:33 | access to parameter x | | CSharp7.cs:158:10:158:17 | this | CSharp7.cs:170:9:170:9 | this access | -| CSharp7.cs:161:18:161:18 | t | CSharp7.cs:161:18:161:18 | t | | CSharp7.cs:161:18:161:18 | t | CSharp7.cs:161:24:161:24 | access to parameter t | | CSharp7.cs:163:9:168:9 | this | CSharp7.cs:166:13:166:16 | this access | -| CSharp7.cs:163:26:163:26 | u | CSharp7.cs:163:26:163:26 | u | | CSharp7.cs:163:26:163:26 | u | CSharp7.cs:167:22:167:22 | access to parameter u | | CSharp7.cs:165:13:165:43 | this | CSharp7.cs:165:37:165:40 | this access | | CSharp7.cs:166:13:166:16 | this access | CSharp7.cs:167:20:167:20 | this access | @@ -156,13 +144,10 @@ | CSharp7.cs:176:16:176:30 | SSA def(src) | CSharp7.cs:181:23:181:25 | access to local variable src | | CSharp7.cs:176:22:176:30 | "tainted" | CSharp7.cs:176:16:176:30 | SSA def(src) | | CSharp7.cs:177:9:177:40 | this | CSharp7.cs:177:31:177:31 | this access | -| CSharp7.cs:177:25:177:25 | s | CSharp7.cs:177:25:177:25 | s | | CSharp7.cs:177:25:177:25 | s | CSharp7.cs:177:33:177:33 | access to parameter s | | CSharp7.cs:177:31:177:34 | call to local function g | CSharp7.cs:177:31:177:39 | ... + ... | | CSharp7.cs:177:38:177:39 | "" | CSharp7.cs:177:31:177:39 | ... + ... | -| CSharp7.cs:178:25:178:25 | s | CSharp7.cs:178:25:178:25 | s | | CSharp7.cs:178:25:178:25 | s | CSharp7.cs:178:31:178:31 | access to parameter s | -| CSharp7.cs:179:25:179:25 | s | CSharp7.cs:179:25:179:25 | s | | CSharp7.cs:179:25:179:25 | s | CSharp7.cs:179:37:179:37 | access to parameter s | | CSharp7.cs:181:21:181:21 | this access | CSharp7.cs:182:21:182:21 | this access | | CSharp7.cs:181:23:181:25 | [post] access to local variable src | CSharp7.cs:182:23:182:25 | access to local variable src | @@ -189,9 +174,7 @@ | CSharp7.cs:199:26:199:35 | [post] this access | CSharp7.cs:200:9:200:18 | this access | | CSharp7.cs:199:26:199:35 | this access | CSharp7.cs:200:9:200:18 | this access | | CSharp7.cs:199:33:199:34 | access to local variable r1 | CSharp7.cs:200:16:200:17 | access to local variable r1 | -| CSharp7.cs:203:24:203:24 | p | CSharp7.cs:203:24:203:24 | p | | CSharp7.cs:203:24:203:24 | p | CSharp7.cs:206:20:206:20 | access to parameter p | -| CSharp7.cs:205:28:205:28 | q | CSharp7.cs:205:28:205:28 | q | | CSharp7.cs:205:28:205:28 | q | CSharp7.cs:205:44:205:44 | access to parameter q | | CSharp7.cs:216:13:216:17 | false | CSharp7.cs:216:9:216:17 | SSA def(x) | | CSharp7.cs:217:17:217:17 | 0 | CSharp7.cs:217:16:217:23 | (..., ...) | @@ -248,13 +231,16 @@ | CSharp7.cs:283:13:283:48 | SSA def(dict) | CSharp7.cs:284:20:284:23 | access to local variable dict | | CSharp7.cs:283:20:283:48 | object creation of type Dictionary | CSharp7.cs:283:13:283:48 | SSA def(dict) | | CSharp7.cs:284:13:284:62 | SSA def(list) | CSharp7.cs:286:39:286:42 | access to local variable list | +| CSharp7.cs:284:20:284:23 | access to local variable dict | CSharp7.cs:284:20:284:62 | [library code] call to method Select | +| CSharp7.cs:284:20:284:62 | [library code] call to method Select | CSharp7.cs:284:20:284:62 | call to method Select | +| CSharp7.cs:284:20:284:62 | [library code] call to method Select | CSharp7.cs:284:32:284:61 | [implicit argument 0] (...) => ... | | CSharp7.cs:284:20:284:62 | call to method Select | CSharp7.cs:284:13:284:62 | SSA def(list) | -| CSharp7.cs:284:32:284:35 | item | CSharp7.cs:284:32:284:35 | item | | CSharp7.cs:284:32:284:35 | item | CSharp7.cs:284:41:284:44 | access to parameter item | -| CSharp7.cs:284:32:284:61 | [output] (...) => ... | CSharp7.cs:284:20:284:62 | call to method Select | +| CSharp7.cs:284:32:284:61 | [output] (...) => ... | CSharp7.cs:284:20:284:62 | [library code] call to method Select | | CSharp7.cs:284:41:284:44 | access to parameter item | CSharp7.cs:284:51:284:54 | access to parameter item | | CSharp7.cs:284:41:284:48 | access to property Key | CSharp7.cs:284:40:284:61 | (..., ...) | -| CSharp7.cs:284:51:284:54 | access to parameter item | CSharp7.cs:284:51:284:60 | access to property Value | +| CSharp7.cs:284:51:284:54 | access to parameter item | CSharp7.cs:284:51:284:60 | [library code] access to property Value | +| CSharp7.cs:284:51:284:60 | [library code] access to property Value | CSharp7.cs:284:51:284:60 | access to property Value | | CSharp7.cs:284:51:284:60 | access to property Value | CSharp7.cs:284:40:284:61 | (..., ...) | | CSharp7.cs:286:39:286:42 | access to local variable list | CSharp7.cs:288:36:288:39 | access to local variable list | | CSharp7.cs:288:36:288:39 | access to local variable list | CSharp7.cs:290:32:290:35 | access to local variable list | diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected index af0e92f2377..a46026ba3da 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected @@ -149,7 +149,10 @@ edges | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | | GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:180:21:180:26 | delegate call : String | | GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | +| GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy : String | GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy [Value] : String | +| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy [Value] : String | GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | +| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | +| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy : String | | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | @@ -300,6 +303,9 @@ nodes | GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | semmle.label | "taint source" : String | | GlobalDataFlow.cs:180:21:180:26 | delegate call : String | semmle.label | delegate call : String | | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | semmle.label | access to local variable sink9 | +| GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy : String | semmle.label | [library code] object creation of type Lazy : String | +| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy [Value] : String | semmle.label | object creation of type Lazy [Value] : String | +| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | semmle.label | access to property Value : String | | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | semmle.label | [output] delegate creation of type Func : String | | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | semmle.label | access to local variable sink10 | | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | semmle.label | access to property OutProperty : String | diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected index 7495630f875..c0422a5f0f5 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected @@ -142,22 +142,28 @@ edges | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | -| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:294:31:294:40 | sinkParam8 : String[] | -| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | -| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | -| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | -| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : String | -| GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... : String | +| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:82:76:82:86 | [implicit argument 0] delegate creation of type Func : String | +| GlobalDataFlow.cs:82:76:82:86 | [implicit argument 0] delegate creation of type Func : String | GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : String | +| GlobalDataFlow.cs:82:76:82:86 | [implicit argument 0] delegate creation of type Func : String | GlobalDataFlow.cs:294:31:294:40 | sinkParam8 : String | +| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | +| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | +| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | +| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:90:83:90:101 | [implicit argument 0] (...) => ... : String | +| GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | GlobalDataFlow.cs:84:117:84:127 | [implicit argument 0] (...) => ... : String | +| GlobalDataFlow.cs:84:117:84:127 | [implicit argument 0] (...) => ... : String | GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... : String | | GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... : String | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | | GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... : String | GlobalDataFlow.cs:86:70:86:113 | (...) ... : String[] | -| GlobalDataFlow.cs:86:70:86:113 | (...) ... : String[] | GlobalDataFlow.cs:86:117:86:127 | [output] (...) => ... : String | +| GlobalDataFlow.cs:86:70:86:113 | (...) ... : String[] | GlobalDataFlow.cs:86:117:86:127 | [implicit argument 1] (...) => ... : String | +| GlobalDataFlow.cs:86:117:86:127 | [implicit argument 1] (...) => ... : String | GlobalDataFlow.cs:86:117:86:127 | [output] (...) => ... : String | | GlobalDataFlow.cs:86:117:86:127 | [output] (...) => ... : String | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | -| GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | GlobalDataFlow.cs:88:83:88:101 | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:83:88:101 | [output] (...) => ... : String | GlobalDataFlow.cs:88:104:88:109 | [output] (...) => ... : String | +| GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | GlobalDataFlow.cs:88:83:88:101 | [implicit argument 1] (...) => ... : String | +| GlobalDataFlow.cs:88:83:88:101 | [implicit argument 1] (...) => ... : String | GlobalDataFlow.cs:88:83:88:101 | [output] (...) => ... : String | +| GlobalDataFlow.cs:88:83:88:101 | [output] (...) => ... : String | GlobalDataFlow.cs:88:104:88:109 | [implicit argument 0] (...) => ... : String | +| GlobalDataFlow.cs:88:104:88:109 | [implicit argument 0] (...) => ... : String | GlobalDataFlow.cs:88:104:88:109 | [output] (...) => ... : String | | GlobalDataFlow.cs:88:104:88:109 | [output] (...) => ... : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : String | GlobalDataFlow.cs:90:83:90:101 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:83:90:101 | [output] (...) => ... : String | GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | +| GlobalDataFlow.cs:90:83:90:101 | [implicit argument 0] (...) => ... : String | GlobalDataFlow.cs:90:83:90:101 | [output] (...) => ... : String | +| GlobalDataFlow.cs:90:83:90:101 | [output] (...) => ... : String | GlobalDataFlow.cs:90:104:90:109 | [implicit argument 0] (...) => ... : String | +| GlobalDataFlow.cs:90:104:90:109 | [implicit argument 0] (...) => ... : String | GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | | GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | | GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | | GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | @@ -173,23 +179,26 @@ edges | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | | GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:180:21:180:26 | delegate call : String | | GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | +| GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy : String | GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy [Value] : String | +| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy [Value] : String | GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | +| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | +| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy : String | | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:212:22:212:28 | access to local variable tainted : IQueryable | -| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:214:22:214:28 | access to local variable tainted : IQueryable | -| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:216:22:216:28 | access to local variable tainted : IQueryable | -| GlobalDataFlow.cs:210:35:210:45 | sinkParam10 : IQueryable | GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:211:71:211:71 | x : IQueryable | GlobalDataFlow.cs:211:89:211:89 | access to parameter x : String | +| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:212:37:212:38 | [implicit argument 0] access to local variable f1 : String | +| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:214:37:214:38 | [implicit argument 0] access to local variable f2 : String | +| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:216:37:216:48 | [implicit argument 0] delegate creation of type Func : String | +| GlobalDataFlow.cs:210:35:210:45 | sinkParam10 : String | GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | +| GlobalDataFlow.cs:211:71:211:71 | x : String | GlobalDataFlow.cs:211:89:211:89 | access to parameter x : String | | GlobalDataFlow.cs:211:89:211:89 | access to parameter x : String | GlobalDataFlow.cs:300:32:300:41 | sinkParam9 : String | -| GlobalDataFlow.cs:212:22:212:28 | access to local variable tainted : IQueryable | GlobalDataFlow.cs:210:35:210:45 | sinkParam10 : IQueryable | -| GlobalDataFlow.cs:212:22:212:28 | access to local variable tainted : IQueryable | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f1 : String | +| GlobalDataFlow.cs:212:37:212:38 | [implicit argument 0] access to local variable f1 : String | GlobalDataFlow.cs:210:35:210:45 | sinkParam10 : String | +| GlobalDataFlow.cs:212:37:212:38 | [implicit argument 0] access to local variable f1 : String | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f1 : String | | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f1 : String | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | -| GlobalDataFlow.cs:214:22:214:28 | access to local variable tainted : IQueryable | GlobalDataFlow.cs:211:71:211:71 | x : IQueryable | -| GlobalDataFlow.cs:214:22:214:28 | access to local variable tainted : IQueryable | GlobalDataFlow.cs:214:37:214:38 | [output] access to local variable f2 : String | +| GlobalDataFlow.cs:214:37:214:38 | [implicit argument 0] access to local variable f2 : String | GlobalDataFlow.cs:211:71:211:71 | x : String | +| GlobalDataFlow.cs:214:37:214:38 | [implicit argument 0] access to local variable f2 : String | GlobalDataFlow.cs:214:37:214:38 | [output] access to local variable f2 : String | | GlobalDataFlow.cs:214:37:214:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | -| GlobalDataFlow.cs:216:22:216:28 | access to local variable tainted : IQueryable | GlobalDataFlow.cs:216:37:216:48 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:216:22:216:28 | access to local variable tainted : IQueryable | GlobalDataFlow.cs:306:32:306:42 | sinkParam11 : IQueryable | -| GlobalDataFlow.cs:216:37:216:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | +| GlobalDataFlow.cs:216:37:216:48 | [implicit argument 0] delegate creation of type Func : String | GlobalDataFlow.cs:216:37:216:48 | [output] delegate creation of type Func : String | +| GlobalDataFlow.cs:216:37:216:48 | [implicit argument 0] delegate creation of type Func : String | GlobalDataFlow.cs:306:32:306:42 | sinkParam11 : String | +| GlobalDataFlow.cs:216:37:216:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | | GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | @@ -199,17 +208,17 @@ edges | GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | | GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | | GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:294:31:294:40 | sinkParam8 : String[] | GlobalDataFlow.cs:296:15:296:24 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:294:31:294:40 | sinkParam8 : String | GlobalDataFlow.cs:296:15:296:24 | access to parameter sinkParam8 | | GlobalDataFlow.cs:300:32:300:41 | sinkParam9 : String | GlobalDataFlow.cs:302:15:302:24 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:306:32:306:42 | sinkParam11 : IQueryable | GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | +| GlobalDataFlow.cs:306:32:306:42 | sinkParam11 : String | GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | | GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | | GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | | GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | | GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | | GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | | GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | -| GlobalDataFlow.cs:336:22:336:35 | "taint source" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | -| GlobalDataFlow.cs:336:22:336:35 | "taint source" : String | GlobalDataFlow.cs:336:22:336:35 | "taint source" : IEnumerable | +| GlobalDataFlow.cs:336:9:336:36 | yield return ...; : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | +| GlobalDataFlow.cs:336:22:336:35 | "taint source" : String | GlobalDataFlow.cs:336:9:336:36 | yield return ...; : IEnumerable | | GlobalDataFlow.cs:361:41:361:41 | x : String | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | | GlobalDataFlow.cs:361:41:361:41 | x : String | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | GlobalDataFlow.cs:53:15:53:15 | x : String | @@ -334,20 +343,26 @@ nodes | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | semmle.label | (...) ... : String[] | | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | semmle.label | access to local variable sink13 | | GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | -| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : T | semmle.label | [output] delegate creation of type Func : T | +| GlobalDataFlow.cs:82:76:82:86 | [implicit argument 0] delegate creation of type Func : String | semmle.label | [implicit argument 0] delegate creation of type Func : String | +| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : String | semmle.label | [output] delegate creation of type Func : String | | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | semmle.label | access to local variable sink14 | | GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | +| GlobalDataFlow.cs:84:117:84:127 | [implicit argument 0] (...) => ... : String | semmle.label | [implicit argument 0] (...) => ... : String | | GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | semmle.label | access to local variable sink15 | | GlobalDataFlow.cs:86:70:86:113 | (...) ... : String[] | semmle.label | (...) ... : String[] | +| GlobalDataFlow.cs:86:117:86:127 | [implicit argument 1] (...) => ... : String | semmle.label | [implicit argument 1] (...) => ... : String | | GlobalDataFlow.cs:86:117:86:127 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | semmle.label | access to local variable sink16 | | GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | +| GlobalDataFlow.cs:88:83:88:101 | [implicit argument 1] (...) => ... : String | semmle.label | [implicit argument 1] (...) => ... : String | | GlobalDataFlow.cs:88:83:88:101 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | +| GlobalDataFlow.cs:88:104:88:109 | [implicit argument 0] (...) => ... : String | semmle.label | [implicit argument 0] (...) => ... : String | | GlobalDataFlow.cs:88:104:88:109 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | semmle.label | access to local variable sink17 | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : String | semmle.label | access to local variable sink14 : String | +| GlobalDataFlow.cs:90:83:90:101 | [implicit argument 0] (...) => ... : String | semmle.label | [implicit argument 0] (...) => ... : String | | GlobalDataFlow.cs:90:83:90:101 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | +| GlobalDataFlow.cs:90:104:90:109 | [implicit argument 0] (...) => ... : String | semmle.label | [implicit argument 0] (...) => ... : String | | GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | semmle.label | access to local variable sink18 | | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | semmle.label | access to local variable sink21 | @@ -371,23 +386,26 @@ nodes | GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | semmle.label | "taint source" : String | | GlobalDataFlow.cs:180:21:180:26 | delegate call : String | semmle.label | delegate call : String | | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | semmle.label | access to local variable sink9 | +| GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy : String | semmle.label | [library code] object creation of type Lazy : String | +| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy [Value] : String | semmle.label | object creation of type Lazy [Value] : String | +| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | semmle.label | access to property Value : String | | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | semmle.label | [output] delegate creation of type Func : String | | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | semmle.label | access to local variable sink10 | | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | semmle.label | access to property OutProperty : String | | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | semmle.label | access to local variable sink19 | | GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:210:35:210:45 | sinkParam10 : IQueryable | semmle.label | sinkParam10 : IQueryable | +| GlobalDataFlow.cs:210:35:210:45 | sinkParam10 : String | semmle.label | sinkParam10 : String | | GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | semmle.label | access to parameter sinkParam10 | -| GlobalDataFlow.cs:211:71:211:71 | x : IQueryable | semmle.label | x : IQueryable | +| GlobalDataFlow.cs:211:71:211:71 | x : String | semmle.label | x : String | | GlobalDataFlow.cs:211:89:211:89 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:212:22:212:28 | access to local variable tainted : IQueryable | semmle.label | access to local variable tainted : IQueryable | +| GlobalDataFlow.cs:212:37:212:38 | [implicit argument 0] access to local variable f1 : String | semmle.label | [implicit argument 0] access to local variable f1 : String | | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f1 : String | semmle.label | [output] access to local variable f1 : String | | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | semmle.label | access to local variable sink24 | -| GlobalDataFlow.cs:214:22:214:28 | access to local variable tainted : IQueryable | semmle.label | access to local variable tainted : IQueryable | +| GlobalDataFlow.cs:214:37:214:38 | [implicit argument 0] access to local variable f2 : String | semmle.label | [implicit argument 0] access to local variable f2 : String | | GlobalDataFlow.cs:214:37:214:38 | [output] access to local variable f2 : String | semmle.label | [output] access to local variable f2 : String | | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | semmle.label | access to local variable sink25 | -| GlobalDataFlow.cs:216:22:216:28 | access to local variable tainted : IQueryable | semmle.label | access to local variable tainted : IQueryable | -| GlobalDataFlow.cs:216:37:216:48 | [output] delegate creation of type Func : T | semmle.label | [output] delegate creation of type Func : T | +| GlobalDataFlow.cs:216:37:216:48 | [implicit argument 0] delegate creation of type Func : String | semmle.label | [implicit argument 0] delegate creation of type Func : String | +| GlobalDataFlow.cs:216:37:216:48 | [output] delegate creation of type Func : String | semmle.label | [output] delegate creation of type Func : String | | GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | semmle.label | access to local variable sink26 | | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | semmle.label | sinkParam0 : String | | GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | semmle.label | access to parameter sinkParam0 : String | @@ -404,18 +422,18 @@ nodes | GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | semmle.label | access to parameter sinkParam6 | | GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | semmle.label | sinkParam7 : String | | GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | semmle.label | access to parameter sinkParam7 | -| GlobalDataFlow.cs:294:31:294:40 | sinkParam8 : String[] | semmle.label | sinkParam8 : String[] | +| GlobalDataFlow.cs:294:31:294:40 | sinkParam8 : String | semmle.label | sinkParam8 : String | | GlobalDataFlow.cs:296:15:296:24 | access to parameter sinkParam8 | semmle.label | access to parameter sinkParam8 | | GlobalDataFlow.cs:300:32:300:41 | sinkParam9 : String | semmle.label | sinkParam9 : String | | GlobalDataFlow.cs:302:15:302:24 | access to parameter sinkParam9 | semmle.label | access to parameter sinkParam9 | -| GlobalDataFlow.cs:306:32:306:42 | sinkParam11 : IQueryable | semmle.label | sinkParam11 : IQueryable | +| GlobalDataFlow.cs:306:32:306:42 | sinkParam11 : String | semmle.label | sinkParam11 : String | | GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | semmle.label | access to parameter sinkParam11 | | GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | semmle.label | "taint source" : String | | GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | | GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | semmle.label | "taint source" : String | | GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | | GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:336:22:336:35 | "taint source" : IEnumerable | semmle.label | "taint source" : IEnumerable | +| GlobalDataFlow.cs:336:9:336:36 | yield return ...; : IEnumerable | semmle.label | yield return ...; : IEnumerable | | GlobalDataFlow.cs:336:22:336:35 | "taint source" : String | semmle.label | "taint source" : String | | GlobalDataFlow.cs:361:41:361:41 | x : String | semmle.label | x : String | | GlobalDataFlow.cs:361:41:361:41 | x : String | semmle.label | x : String | diff --git a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected index ce4eba806a2..f6accf82f4e 100644 --- a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected @@ -1,3 +1,4 @@ +callableFlow | LibraryTypeDataFlow.DataContract.get_AString() | qualifier -> return | false | | System.Array.Add(object) | argument 0 -> qualifier | false | | System.Array.AsReadOnly(T[]) | qualifier -> return | false | @@ -661,10 +662,6 @@ | System.Int32.TryParse(string, NumberStyles, IFormatProvider, out int) | argument 0 -> return | false | | System.Int32.TryParse(string, out int) | argument 0 -> argument 1 | false | | System.Int32.TryParse(string, out int) | argument 0 -> return | false | -| System.Lazy<>.Lazy(Func) | output from argument 0 -> return | true | -| System.Lazy<>.Lazy(Func, LazyThreadSafetyMode) | output from argument 0 -> return | true | -| System.Lazy<>.Lazy(Func, bool) | output from argument 0 -> return | true | -| System.Lazy<>.get_Value() | qualifier -> return | true | | System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | argument 0 -> parameter 1 of argument 2 | false | | System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | argument 1 -> parameter 0 of argument 2 | false | | System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | output from argument 2 -> parameter 0 of argument 3 | false | @@ -1686,3 +1683,7 @@ | System.Web.HttpUtility.HtmlEncode(string) | argument 0 -> return | false | | System.Web.HttpUtility.UrlEncode(string) | argument 0 -> return | false | | System.Web.UI.WebControls.TextBox.get_Text() | qualifier -> return | false | +callableFlowAp +| System.Lazy<>.Lazy(Func) | output from argument 0 [] -> return [Value] | +| System.Lazy<>.Lazy(Func, LazyThreadSafetyMode) | output from argument 0 [] -> return [Value] | +| System.Lazy<>.Lazy(Func, bool) | output from argument 0 [] -> return [Value] | diff --git a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.ql b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.ql index 2c050ebd399..db19f91b54a 100644 --- a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.ql +++ b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.ql @@ -1,22 +1,27 @@ import semmle.code.csharp.dataflow.LibraryTypeDataFlow -predicate callableFlow(string callable, string flow, boolean preservesValue) { +query predicate callableFlow(string callable, string flow, boolean preservesValue) { exists(LibraryTypeDataFlow x, CallableFlowSource source, CallableFlowSink sink, Callable c | c.(Modifiable).isPublic() and c.getDeclaringType().isPublic() and x.callableFlow(source, sink, c, preservesValue) and callable = c.getQualifiedNameWithTypes() and - flow = source.toString() + " -> " + sink.toString() + flow = source + " -> " + sink and + // Remove certain results to make the test output consistent + // between different versions of .NET Core. + not callable = "System.IO.FileStream.CopyToAsync(Stream, int, CancellationToken)" ) } -from string entity, string flow, boolean preservesValue -where - callableFlow(entity, flow, preservesValue) and - /* - * Remove certain results to make the test output consistent - * between different versions of .NET Core. - */ - - not entity = "System.IO.FileStream.CopyToAsync(Stream, int, CancellationToken)" -select entity, flow, preservesValue +query predicate callableFlowAp(string callable, string flow) { + exists( + LibraryTypeDataFlow x, CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, + AccessPath sinkAp, Callable c + | + c.(Modifiable).isPublic() and + c.getDeclaringType().isPublic() and + x.callableFlow(source, sourceAp, sink, sinkAp, c) and + callable = c.getQualifiedNameWithTypes() and + flow = source + " [" + sourceAp + "] -> " + sink + " [" + sinkAp + "]" + ) +} diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected index e3166a0df30..f641a355f83 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -143,8 +143,9 @@ | LocalDataFlow.cs:128:15:128:20 | [post] access to local variable sink49 | LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | | LocalDataFlow.cs:128:15:128:20 | access to local variable sink49 | LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | | LocalDataFlow.cs:129:13:129:40 | SSA def(sink50) | LocalDataFlow.cs:130:15:130:20 | access to local variable sink50 | +| LocalDataFlow.cs:129:22:129:40 | [library code] call to method Copy | LocalDataFlow.cs:129:22:129:40 | call to method Copy | | LocalDataFlow.cs:129:22:129:40 | call to method Copy | LocalDataFlow.cs:129:13:129:40 | SSA def(sink50) | -| LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | LocalDataFlow.cs:129:22:129:40 | call to method Copy | +| LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | LocalDataFlow.cs:129:22:129:40 | [library code] call to method Copy | | LocalDataFlow.cs:130:15:130:20 | [post] access to local variable sink50 | LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | | LocalDataFlow.cs:130:15:130:20 | access to local variable sink50 | LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | | LocalDataFlow.cs:131:13:131:54 | SSA def(sink51) | LocalDataFlow.cs:132:15:132:20 | access to local variable sink51 | @@ -189,8 +190,9 @@ | LocalDataFlow.cs:152:15:152:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | | LocalDataFlow.cs:152:15:152:22 | access to local variable nonSink0 | LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | | LocalDataFlow.cs:153:9:153:40 | SSA def(nonSink0) | LocalDataFlow.cs:154:15:154:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:153:20:153:40 | [library code] call to method Copy | LocalDataFlow.cs:153:20:153:40 | call to method Copy | | LocalDataFlow.cs:153:20:153:40 | call to method Copy | LocalDataFlow.cs:153:9:153:40 | SSA def(nonSink0) | -| LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | LocalDataFlow.cs:153:20:153:40 | call to method Copy | +| LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | LocalDataFlow.cs:153:20:153:40 | [library code] call to method Copy | | LocalDataFlow.cs:154:15:154:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | | LocalDataFlow.cs:154:15:154:22 | access to local variable nonSink0 | LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | | LocalDataFlow.cs:155:9:155:54 | SSA def(nonSink0) | LocalDataFlow.cs:156:15:156:22 | access to local variable nonSink0 | @@ -284,7 +286,8 @@ | LocalDataFlow.cs:216:15:216:22 | access to local variable nonSink0 | LocalDataFlow.cs:225:28:225:35 | access to local variable nonSink0 | | LocalDataFlow.cs:219:13:219:127 | SSA def(sink33) | LocalDataFlow.cs:220:15:220:20 | access to local variable sink33 | | LocalDataFlow.cs:219:22:219:127 | (...) ... | LocalDataFlow.cs:219:13:219:127 | SSA def(sink33) | -| LocalDataFlow.cs:219:30:219:119 | call to method Insert | LocalDataFlow.cs:219:30:219:127 | call to method Clone | +| LocalDataFlow.cs:219:30:219:119 | call to method Insert | LocalDataFlow.cs:219:30:219:127 | [library code] call to method Clone | +| LocalDataFlow.cs:219:30:219:127 | [library code] call to method Clone | LocalDataFlow.cs:219:30:219:127 | call to method Clone | | LocalDataFlow.cs:219:30:219:127 | call to method Clone | LocalDataFlow.cs:219:22:219:127 | (...) ... | | LocalDataFlow.cs:220:15:220:20 | [post] access to local variable sink33 | LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | | LocalDataFlow.cs:220:15:220:20 | access to local variable sink33 | LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | @@ -294,7 +297,8 @@ | LocalDataFlow.cs:221:22:221:63 | call to method Split | LocalDataFlow.cs:221:13:221:63 | SSA def(sink48) | | LocalDataFlow.cs:225:9:225:127 | SSA def(nonSink0) | LocalDataFlow.cs:226:15:226:22 | access to local variable nonSink0 | | LocalDataFlow.cs:225:20:225:127 | (...) ... | LocalDataFlow.cs:225:9:225:127 | SSA def(nonSink0) | -| LocalDataFlow.cs:225:28:225:119 | call to method Insert | LocalDataFlow.cs:225:28:225:127 | call to method Clone | +| LocalDataFlow.cs:225:28:225:119 | call to method Insert | LocalDataFlow.cs:225:28:225:127 | [library code] call to method Clone | +| LocalDataFlow.cs:225:28:225:127 | [library code] call to method Clone | LocalDataFlow.cs:225:28:225:127 | call to method Clone | | LocalDataFlow.cs:225:28:225:127 | call to method Clone | LocalDataFlow.cs:225:20:225:127 | (...) ... | | LocalDataFlow.cs:226:15:226:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | | LocalDataFlow.cs:226:15:226:22 | access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | @@ -358,16 +362,18 @@ | LocalDataFlow.cs:270:9:270:41 | SSA def(nonSink0) | LocalDataFlow.cs:271:15:271:22 | access to local variable nonSink0 | | LocalDataFlow.cs:270:20:270:41 | access to property Text | LocalDataFlow.cs:270:9:270:41 | SSA def(nonSink0) | | LocalDataFlow.cs:274:13:274:51 | SSA def(sink67) | LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | +| LocalDataFlow.cs:274:22:274:51 | [library code] call to method Run | LocalDataFlow.cs:274:22:274:51 | call to method Run | | LocalDataFlow.cs:274:22:274:51 | call to method Run | LocalDataFlow.cs:274:13:274:51 | SSA def(sink67) | -| LocalDataFlow.cs:274:31:274:50 | [output] (...) => ... | LocalDataFlow.cs:274:22:274:51 | call to method Run | +| LocalDataFlow.cs:274:31:274:50 | [output] (...) => ... | LocalDataFlow.cs:274:22:274:51 | [library code] call to method Run | | LocalDataFlow.cs:275:15:275:20 | [post] access to local variable sink67 | LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | | LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | | LocalDataFlow.cs:276:13:276:33 | SSA def(sink68) | LocalDataFlow.cs:277:15:277:20 | access to local variable sink68 | | LocalDataFlow.cs:276:22:276:33 | await ... | LocalDataFlow.cs:276:13:276:33 | SSA def(sink68) | | LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | LocalDataFlow.cs:276:22:276:33 | await ... | | LocalDataFlow.cs:280:13:280:42 | SSA def(nonSink21) | LocalDataFlow.cs:281:15:281:23 | access to local variable nonSink21 | +| LocalDataFlow.cs:280:25:280:42 | [library code] call to method Run | LocalDataFlow.cs:280:25:280:42 | call to method Run | | LocalDataFlow.cs:280:25:280:42 | call to method Run | LocalDataFlow.cs:280:13:280:42 | SSA def(nonSink21) | -| LocalDataFlow.cs:280:34:280:41 | [output] (...) => ... | LocalDataFlow.cs:280:25:280:42 | call to method Run | +| LocalDataFlow.cs:280:34:280:41 | [output] (...) => ... | LocalDataFlow.cs:280:25:280:42 | [library code] call to method Run | | LocalDataFlow.cs:281:15:281:23 | [post] access to local variable nonSink21 | LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | | LocalDataFlow.cs:281:15:281:23 | access to local variable nonSink21 | LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | | LocalDataFlow.cs:282:9:282:34 | SSA def(nonSink0) | LocalDataFlow.cs:283:15:283:22 | access to local variable nonSink0 | diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected index 4cb33d841cb..77195b49f3d 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected @@ -24,7 +24,6 @@ | Capture.cs:58:21:58:21 | 1 | Capture.cs:58:17:58:21 | SSA def(i) | | Capture.cs:61:17:61:17 | 1 | Capture.cs:61:13:61:17 | SSA def(i) | | Capture.cs:63:9:63:17 | SSA call def(i) | Capture.cs:64:13:64:13 | access to local variable i | -| LocalDataFlow.cs:49:30:49:30 | b | LocalDataFlow.cs:49:30:49:30 | b | | LocalDataFlow.cs:49:30:49:30 | b | LocalDataFlow.cs:85:21:85:21 | access to parameter b | | LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | | LocalDataFlow.cs:52:21:52:34 | "taint source" | LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | @@ -108,142 +107,184 @@ | LocalDataFlow.cs:106:15:106:22 | [post] access to local variable nonSink3 | LocalDataFlow.cs:171:33:171:40 | access to local variable nonSink3 | | LocalDataFlow.cs:106:15:106:22 | access to local variable nonSink3 | LocalDataFlow.cs:171:33:171:40 | access to local variable nonSink3 | | LocalDataFlow.cs:109:13:109:39 | SSA def(sink15) | LocalDataFlow.cs:110:15:110:20 | access to local variable sink15 | +| LocalDataFlow.cs:109:22:109:39 | [library code] call to method Parse | LocalDataFlow.cs:109:22:109:39 | call to method Parse | | LocalDataFlow.cs:109:22:109:39 | call to method Parse | LocalDataFlow.cs:109:13:109:39 | SSA def(sink15) | | LocalDataFlow.cs:109:34:109:38 | [post] access to local variable sink9 | LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | -| LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | LocalDataFlow.cs:109:22:109:39 | call to method Parse | +| LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | LocalDataFlow.cs:109:22:109:39 | [library code] call to method Parse | | LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | | LocalDataFlow.cs:110:15:110:20 | access to local variable sink15 | LocalDataFlow.cs:161:22:161:27 | access to local variable sink15 | | LocalDataFlow.cs:112:13:112:56 | SSA def(sink16) | LocalDataFlow.cs:113:15:113:20 | access to local variable sink16 | +| LocalDataFlow.cs:112:22:112:56 | [library code] call to method TryParse | LocalDataFlow.cs:112:22:112:56 | call to method TryParse | | LocalDataFlow.cs:112:22:112:56 | call to method TryParse | LocalDataFlow.cs:112:13:112:56 | SSA def(sink16) | | LocalDataFlow.cs:112:37:112:41 | [post] access to local variable sink9 | LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | -| LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | LocalDataFlow.cs:112:22:112:56 | call to method TryParse | +| LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | LocalDataFlow.cs:112:22:112:56 | [library code] call to method TryParse | +| LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | LocalDataFlow.cs:112:22:112:56 | [library code] call to method TryParse | | LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | | LocalDataFlow.cs:114:13:114:49 | SSA def(sink17) | LocalDataFlow.cs:115:15:115:20 | access to local variable sink17 | | LocalDataFlow.cs:114:22:114:29 | [post] access to local variable nonSink0 | LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | -| LocalDataFlow.cs:114:22:114:29 | access to local variable nonSink0 | LocalDataFlow.cs:114:22:114:49 | call to method Replace | +| LocalDataFlow.cs:114:22:114:29 | access to local variable nonSink0 | LocalDataFlow.cs:114:22:114:49 | [library code] call to method Replace | | LocalDataFlow.cs:114:22:114:29 | access to local variable nonSink0 | LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | +| LocalDataFlow.cs:114:22:114:49 | [library code] call to method Replace | LocalDataFlow.cs:114:22:114:49 | call to method Replace | +| LocalDataFlow.cs:114:22:114:49 | [library code] call to method Replace | LocalDataFlow.cs:114:22:114:49 | call to method Replace | | LocalDataFlow.cs:114:22:114:49 | call to method Replace | LocalDataFlow.cs:114:13:114:49 | SSA def(sink17) | | LocalDataFlow.cs:114:44:114:48 | [post] access to local variable sink9 | LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | -| LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | LocalDataFlow.cs:114:22:114:49 | call to method Replace | +| LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | LocalDataFlow.cs:114:22:114:49 | [library code] call to method Replace | | LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | | LocalDataFlow.cs:116:13:116:51 | SSA def(sink18) | LocalDataFlow.cs:117:15:117:20 | access to local variable sink18 | +| LocalDataFlow.cs:116:22:116:51 | [library code] call to method Format | LocalDataFlow.cs:116:22:116:51 | call to method Format | +| LocalDataFlow.cs:116:22:116:51 | [library code] call to method Format | LocalDataFlow.cs:116:22:116:51 | call to method Format | | LocalDataFlow.cs:116:22:116:51 | call to method Format | LocalDataFlow.cs:116:13:116:51 | SSA def(sink18) | | LocalDataFlow.cs:116:36:116:43 | [post] access to local variable nonSink0 | LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | LocalDataFlow.cs:116:22:116:51 | call to method Format | +| LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | LocalDataFlow.cs:116:22:116:51 | [library code] call to method Format | | LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | | LocalDataFlow.cs:116:46:116:50 | [post] access to local variable sink9 | LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | -| LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | LocalDataFlow.cs:116:22:116:51 | call to method Format | +| LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | LocalDataFlow.cs:116:22:116:51 | [library code] call to method Format | | LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | | LocalDataFlow.cs:117:15:117:20 | [post] access to local variable sink18 | LocalDataFlow.cs:118:36:118:41 | access to local variable sink18 | | LocalDataFlow.cs:117:15:117:20 | access to local variable sink18 | LocalDataFlow.cs:118:36:118:41 | access to local variable sink18 | | LocalDataFlow.cs:118:13:118:52 | SSA def(sink19) | LocalDataFlow.cs:119:15:119:20 | access to local variable sink19 | +| LocalDataFlow.cs:118:22:118:52 | [library code] call to method Format | LocalDataFlow.cs:118:22:118:52 | call to method Format | +| LocalDataFlow.cs:118:22:118:52 | [library code] call to method Format | LocalDataFlow.cs:118:22:118:52 | call to method Format | | LocalDataFlow.cs:118:22:118:52 | call to method Format | LocalDataFlow.cs:118:13:118:52 | SSA def(sink19) | -| LocalDataFlow.cs:118:36:118:41 | access to local variable sink18 | LocalDataFlow.cs:118:22:118:52 | call to method Format | +| LocalDataFlow.cs:118:36:118:41 | access to local variable sink18 | LocalDataFlow.cs:118:22:118:52 | [library code] call to method Format | | LocalDataFlow.cs:118:44:118:51 | [post] access to local variable nonSink0 | LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | LocalDataFlow.cs:118:22:118:52 | call to method Format | +| LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | LocalDataFlow.cs:118:22:118:52 | [library code] call to method Format | | LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | | LocalDataFlow.cs:120:13:120:38 | SSA def(sink45) | LocalDataFlow.cs:121:15:121:20 | access to local variable sink45 | +| LocalDataFlow.cs:120:22:120:38 | [library code] call to method Parse | LocalDataFlow.cs:120:22:120:38 | call to method Parse | | LocalDataFlow.cs:120:22:120:38 | call to method Parse | LocalDataFlow.cs:120:13:120:38 | SSA def(sink45) | | LocalDataFlow.cs:120:33:120:37 | [post] access to local variable sink9 | LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | -| LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | LocalDataFlow.cs:120:22:120:38 | call to method Parse | +| LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | LocalDataFlow.cs:120:22:120:38 | [library code] call to method Parse | | LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | | LocalDataFlow.cs:123:13:123:56 | SSA def(sink46) | LocalDataFlow.cs:124:15:124:20 | access to local variable sink46 | +| LocalDataFlow.cs:123:22:123:56 | [library code] call to method TryParse | LocalDataFlow.cs:123:22:123:56 | call to method TryParse | | LocalDataFlow.cs:123:22:123:56 | call to method TryParse | LocalDataFlow.cs:123:13:123:56 | SSA def(sink46) | | LocalDataFlow.cs:123:36:123:40 | [post] access to local variable sink9 | LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | -| LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | LocalDataFlow.cs:123:22:123:56 | call to method TryParse | +| LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | LocalDataFlow.cs:123:22:123:56 | [library code] call to method TryParse | +| LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | LocalDataFlow.cs:123:22:123:56 | [library code] call to method TryParse | | LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | | LocalDataFlow.cs:124:15:124:20 | access to local variable sink46 | LocalDataFlow.cs:125:37:125:42 | access to local variable sink46 | | LocalDataFlow.cs:125:13:125:43 | SSA def(sink47) | LocalDataFlow.cs:126:15:126:20 | access to local variable sink47 | +| LocalDataFlow.cs:125:22:125:43 | [library code] call to method ToByte | LocalDataFlow.cs:125:22:125:43 | call to method ToByte | | LocalDataFlow.cs:125:22:125:43 | call to method ToByte | LocalDataFlow.cs:125:13:125:43 | SSA def(sink47) | -| LocalDataFlow.cs:125:37:125:42 | access to local variable sink46 | LocalDataFlow.cs:125:22:125:43 | call to method ToByte | +| LocalDataFlow.cs:125:37:125:42 | access to local variable sink46 | LocalDataFlow.cs:125:22:125:43 | [library code] call to method ToByte | | LocalDataFlow.cs:126:15:126:20 | access to local variable sink47 | LocalDataFlow.cs:127:40:127:45 | access to local variable sink47 | | LocalDataFlow.cs:127:13:127:46 | SSA def(sink49) | LocalDataFlow.cs:128:15:128:20 | access to local variable sink49 | +| LocalDataFlow.cs:127:22:127:46 | [library code] call to method Concat | LocalDataFlow.cs:127:22:127:46 | call to method Concat | +| LocalDataFlow.cs:127:22:127:46 | [library code] call to method Concat | LocalDataFlow.cs:127:22:127:46 | call to method Concat | | LocalDataFlow.cs:127:22:127:46 | call to method Concat | LocalDataFlow.cs:127:13:127:46 | SSA def(sink49) | -| LocalDataFlow.cs:127:36:127:37 | "" | LocalDataFlow.cs:127:22:127:46 | call to method Concat | -| LocalDataFlow.cs:127:40:127:45 | (...) ... | LocalDataFlow.cs:127:22:127:46 | call to method Concat | +| LocalDataFlow.cs:127:36:127:37 | "" | LocalDataFlow.cs:127:22:127:46 | [library code] call to method Concat | +| LocalDataFlow.cs:127:40:127:45 | (...) ... | LocalDataFlow.cs:127:22:127:46 | [library code] call to method Concat | | LocalDataFlow.cs:127:40:127:45 | access to local variable sink47 | LocalDataFlow.cs:127:40:127:45 | (...) ... | | LocalDataFlow.cs:128:15:128:20 | [post] access to local variable sink49 | LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | | LocalDataFlow.cs:128:15:128:20 | access to local variable sink49 | LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | | LocalDataFlow.cs:129:13:129:40 | SSA def(sink50) | LocalDataFlow.cs:130:15:130:20 | access to local variable sink50 | +| LocalDataFlow.cs:129:22:129:40 | [library code] call to method Copy | LocalDataFlow.cs:129:22:129:40 | call to method Copy | | LocalDataFlow.cs:129:22:129:40 | call to method Copy | LocalDataFlow.cs:129:13:129:40 | SSA def(sink50) | -| LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | LocalDataFlow.cs:129:22:129:40 | call to method Copy | +| LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | LocalDataFlow.cs:129:22:129:40 | [library code] call to method Copy | | LocalDataFlow.cs:130:15:130:20 | [post] access to local variable sink50 | LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | | LocalDataFlow.cs:130:15:130:20 | access to local variable sink50 | LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | | LocalDataFlow.cs:131:13:131:54 | SSA def(sink51) | LocalDataFlow.cs:132:15:132:20 | access to local variable sink51 | +| LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | LocalDataFlow.cs:131:22:131:54 | call to method Join | +| LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | LocalDataFlow.cs:131:22:131:54 | call to method Join | +| LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | LocalDataFlow.cs:131:22:131:54 | call to method Join | +| LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | LocalDataFlow.cs:131:22:131:54 | call to method Join | | LocalDataFlow.cs:131:22:131:54 | call to method Join | LocalDataFlow.cs:131:13:131:54 | SSA def(sink51) | -| LocalDataFlow.cs:131:34:131:37 | ", " | LocalDataFlow.cs:131:22:131:54 | call to method Join | -| LocalDataFlow.cs:131:40:131:41 | "" | LocalDataFlow.cs:131:22:131:54 | call to method Join | -| LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | LocalDataFlow.cs:131:22:131:54 | call to method Join | -| LocalDataFlow.cs:131:52:131:53 | "" | LocalDataFlow.cs:131:22:131:54 | call to method Join | +| LocalDataFlow.cs:131:34:131:37 | ", " | LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | +| LocalDataFlow.cs:131:40:131:41 | "" | LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | +| LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | +| LocalDataFlow.cs:131:52:131:53 | "" | LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | | LocalDataFlow.cs:132:15:132:20 | [post] access to local variable sink51 | LocalDataFlow.cs:133:35:133:40 | access to local variable sink51 | | LocalDataFlow.cs:132:15:132:20 | access to local variable sink51 | LocalDataFlow.cs:133:35:133:40 | access to local variable sink51 | | LocalDataFlow.cs:133:13:133:41 | SSA def(sink52) | LocalDataFlow.cs:134:15:134:20 | access to local variable sink52 | -| LocalDataFlow.cs:133:22:133:23 | "" | LocalDataFlow.cs:133:22:133:41 | call to method Insert | +| LocalDataFlow.cs:133:22:133:23 | "" | LocalDataFlow.cs:133:22:133:41 | [library code] call to method Insert | +| LocalDataFlow.cs:133:22:133:41 | [library code] call to method Insert | LocalDataFlow.cs:133:22:133:41 | call to method Insert | +| LocalDataFlow.cs:133:22:133:41 | [library code] call to method Insert | LocalDataFlow.cs:133:22:133:41 | call to method Insert | | LocalDataFlow.cs:133:22:133:41 | call to method Insert | LocalDataFlow.cs:133:13:133:41 | SSA def(sink52) | -| LocalDataFlow.cs:133:35:133:40 | access to local variable sink51 | LocalDataFlow.cs:133:22:133:41 | call to method Insert | +| LocalDataFlow.cs:133:35:133:40 | access to local variable sink51 | LocalDataFlow.cs:133:22:133:41 | [library code] call to method Insert | | LocalDataFlow.cs:137:9:137:40 | SSA def(nonSink2) | LocalDataFlow.cs:138:15:138:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:137:20:137:40 | [library code] call to method Parse | LocalDataFlow.cs:137:20:137:40 | call to method Parse | | LocalDataFlow.cs:137:20:137:40 | call to method Parse | LocalDataFlow.cs:137:9:137:40 | SSA def(nonSink2) | | LocalDataFlow.cs:137:32:137:39 | [post] access to local variable nonSink0 | LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | LocalDataFlow.cs:137:20:137:40 | call to method Parse | +| LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | LocalDataFlow.cs:137:20:137:40 | [library code] call to method Parse | | LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | | LocalDataFlow.cs:139:13:139:61 | SSA def(nonSink7) | LocalDataFlow.cs:140:15:140:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:139:24:139:61 | [library code] call to method TryParse | LocalDataFlow.cs:139:24:139:61 | call to method TryParse | | LocalDataFlow.cs:139:24:139:61 | call to method TryParse | LocalDataFlow.cs:139:13:139:61 | SSA def(nonSink7) | | LocalDataFlow.cs:139:39:139:46 | [post] access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | LocalDataFlow.cs:139:24:139:61 | call to method TryParse | +| LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | LocalDataFlow.cs:139:24:139:61 | [library code] call to method TryParse | +| LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | LocalDataFlow.cs:139:24:139:61 | [library code] call to method TryParse | | LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | | LocalDataFlow.cs:141:9:141:50 | SSA def(nonSink0) | LocalDataFlow.cs:142:15:142:22 | access to local variable nonSink0 | | LocalDataFlow.cs:141:20:141:27 | [post] access to local variable nonSink0 | LocalDataFlow.cs:141:42:141:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:50 | call to method Replace | +| LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:50 | [library code] call to method Replace | | LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | LocalDataFlow.cs:141:42:141:49 | access to local variable nonSink0 | +| LocalDataFlow.cs:141:20:141:50 | [library code] call to method Replace | LocalDataFlow.cs:141:20:141:50 | call to method Replace | +| LocalDataFlow.cs:141:20:141:50 | [library code] call to method Replace | LocalDataFlow.cs:141:20:141:50 | call to method Replace | | LocalDataFlow.cs:141:20:141:50 | call to method Replace | LocalDataFlow.cs:141:9:141:50 | SSA def(nonSink0) | -| LocalDataFlow.cs:141:42:141:49 | access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:50 | call to method Replace | +| LocalDataFlow.cs:141:42:141:49 | access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:50 | [library code] call to method Replace | | LocalDataFlow.cs:142:15:142:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | | LocalDataFlow.cs:142:15:142:22 | access to local variable nonSink0 | LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | | LocalDataFlow.cs:143:9:143:52 | SSA def(nonSink0) | LocalDataFlow.cs:144:15:144:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:143:20:143:52 | [library code] call to method Format | LocalDataFlow.cs:143:20:143:52 | call to method Format | +| LocalDataFlow.cs:143:20:143:52 | [library code] call to method Format | LocalDataFlow.cs:143:20:143:52 | call to method Format | | LocalDataFlow.cs:143:20:143:52 | call to method Format | LocalDataFlow.cs:143:9:143:52 | SSA def(nonSink0) | | LocalDataFlow.cs:143:34:143:41 | [post] access to local variable nonSink0 | LocalDataFlow.cs:143:44:143:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | LocalDataFlow.cs:143:20:143:52 | call to method Format | +| LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | LocalDataFlow.cs:143:20:143:52 | [library code] call to method Format | | LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | LocalDataFlow.cs:143:44:143:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:143:44:143:51 | access to local variable nonSink0 | LocalDataFlow.cs:143:20:143:52 | call to method Format | +| LocalDataFlow.cs:143:44:143:51 | access to local variable nonSink0 | LocalDataFlow.cs:143:20:143:52 | [library code] call to method Format | | LocalDataFlow.cs:144:15:144:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | | LocalDataFlow.cs:144:15:144:22 | access to local variable nonSink0 | LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | | LocalDataFlow.cs:145:9:145:39 | SSA def(nonSink7) | LocalDataFlow.cs:146:15:146:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:145:20:145:39 | [library code] call to method Parse | LocalDataFlow.cs:145:20:145:39 | call to method Parse | | LocalDataFlow.cs:145:20:145:39 | call to method Parse | LocalDataFlow.cs:145:9:145:39 | SSA def(nonSink7) | | LocalDataFlow.cs:145:31:145:38 | [post] access to local variable nonSink0 | LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | LocalDataFlow.cs:145:20:145:39 | call to method Parse | +| LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | LocalDataFlow.cs:145:20:145:39 | [library code] call to method Parse | | LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | | LocalDataFlow.cs:147:9:147:57 | SSA def(nonSink7) | LocalDataFlow.cs:148:15:148:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:147:20:147:57 | [library code] call to method TryParse | LocalDataFlow.cs:147:20:147:57 | call to method TryParse | | LocalDataFlow.cs:147:20:147:57 | call to method TryParse | LocalDataFlow.cs:147:9:147:57 | SSA def(nonSink7) | -| LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | LocalDataFlow.cs:147:20:147:57 | call to method TryParse | +| LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | LocalDataFlow.cs:147:20:147:57 | [library code] call to method TryParse | +| LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | LocalDataFlow.cs:147:20:147:57 | [library code] call to method TryParse | | LocalDataFlow.cs:148:15:148:22 | access to local variable nonSink7 | LocalDataFlow.cs:149:40:149:47 | access to local variable nonSink7 | | LocalDataFlow.cs:149:13:149:48 | SSA def(nonSink14) | LocalDataFlow.cs:150:15:150:23 | access to local variable nonSink14 | +| LocalDataFlow.cs:149:25:149:48 | [library code] call to method ToByte | LocalDataFlow.cs:149:25:149:48 | call to method ToByte | | LocalDataFlow.cs:149:25:149:48 | call to method ToByte | LocalDataFlow.cs:149:13:149:48 | SSA def(nonSink14) | -| LocalDataFlow.cs:149:40:149:47 | access to local variable nonSink7 | LocalDataFlow.cs:149:25:149:48 | call to method ToByte | +| LocalDataFlow.cs:149:40:149:47 | access to local variable nonSink7 | LocalDataFlow.cs:149:25:149:48 | [library code] call to method ToByte | | LocalDataFlow.cs:149:40:149:47 | access to local variable nonSink7 | LocalDataFlow.cs:151:38:151:45 | access to local variable nonSink7 | | LocalDataFlow.cs:151:9:151:46 | SSA def(nonSink0) | LocalDataFlow.cs:152:15:152:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:151:20:151:46 | [library code] call to method Concat | LocalDataFlow.cs:151:20:151:46 | call to method Concat | +| LocalDataFlow.cs:151:20:151:46 | [library code] call to method Concat | LocalDataFlow.cs:151:20:151:46 | call to method Concat | | LocalDataFlow.cs:151:20:151:46 | call to method Concat | LocalDataFlow.cs:151:9:151:46 | SSA def(nonSink0) | -| LocalDataFlow.cs:151:34:151:35 | "" | LocalDataFlow.cs:151:20:151:46 | call to method Concat | -| LocalDataFlow.cs:151:38:151:45 | (...) ... | LocalDataFlow.cs:151:20:151:46 | call to method Concat | +| LocalDataFlow.cs:151:34:151:35 | "" | LocalDataFlow.cs:151:20:151:46 | [library code] call to method Concat | +| LocalDataFlow.cs:151:38:151:45 | (...) ... | LocalDataFlow.cs:151:20:151:46 | [library code] call to method Concat | | LocalDataFlow.cs:151:38:151:45 | access to local variable nonSink7 | LocalDataFlow.cs:151:38:151:45 | (...) ... | | LocalDataFlow.cs:152:15:152:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | | LocalDataFlow.cs:152:15:152:22 | access to local variable nonSink0 | LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | | LocalDataFlow.cs:153:9:153:40 | SSA def(nonSink0) | LocalDataFlow.cs:154:15:154:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:153:20:153:40 | [library code] call to method Copy | LocalDataFlow.cs:153:20:153:40 | call to method Copy | | LocalDataFlow.cs:153:20:153:40 | call to method Copy | LocalDataFlow.cs:153:9:153:40 | SSA def(nonSink0) | -| LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | LocalDataFlow.cs:153:20:153:40 | call to method Copy | +| LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | LocalDataFlow.cs:153:20:153:40 | [library code] call to method Copy | | LocalDataFlow.cs:154:15:154:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | | LocalDataFlow.cs:154:15:154:22 | access to local variable nonSink0 | LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | | LocalDataFlow.cs:155:9:155:54 | SSA def(nonSink0) | LocalDataFlow.cs:156:15:156:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | LocalDataFlow.cs:155:20:155:54 | call to method Join | +| LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | LocalDataFlow.cs:155:20:155:54 | call to method Join | +| LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | LocalDataFlow.cs:155:20:155:54 | call to method Join | +| LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | LocalDataFlow.cs:155:20:155:54 | call to method Join | | LocalDataFlow.cs:155:20:155:54 | call to method Join | LocalDataFlow.cs:155:9:155:54 | SSA def(nonSink0) | -| LocalDataFlow.cs:155:32:155:35 | ", " | LocalDataFlow.cs:155:20:155:54 | call to method Join | -| LocalDataFlow.cs:155:38:155:39 | "" | LocalDataFlow.cs:155:20:155:54 | call to method Join | -| LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | LocalDataFlow.cs:155:20:155:54 | call to method Join | -| LocalDataFlow.cs:155:52:155:53 | "" | LocalDataFlow.cs:155:20:155:54 | call to method Join | +| LocalDataFlow.cs:155:32:155:35 | ", " | LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | +| LocalDataFlow.cs:155:38:155:39 | "" | LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | +| LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | +| LocalDataFlow.cs:155:52:155:53 | "" | LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | | LocalDataFlow.cs:156:15:156:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:157:33:157:40 | access to local variable nonSink0 | | LocalDataFlow.cs:156:15:156:22 | access to local variable nonSink0 | LocalDataFlow.cs:157:33:157:40 | access to local variable nonSink0 | | LocalDataFlow.cs:157:9:157:41 | SSA def(nonSink0) | LocalDataFlow.cs:158:15:158:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:157:20:157:21 | "" | LocalDataFlow.cs:157:20:157:41 | call to method Insert | +| LocalDataFlow.cs:157:20:157:21 | "" | LocalDataFlow.cs:157:20:157:41 | [library code] call to method Insert | +| LocalDataFlow.cs:157:20:157:41 | [library code] call to method Insert | LocalDataFlow.cs:157:20:157:41 | call to method Insert | +| LocalDataFlow.cs:157:20:157:41 | [library code] call to method Insert | LocalDataFlow.cs:157:20:157:41 | call to method Insert | | LocalDataFlow.cs:157:20:157:41 | call to method Insert | LocalDataFlow.cs:157:9:157:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:157:33:157:40 | access to local variable nonSink0 | LocalDataFlow.cs:157:20:157:41 | call to method Insert | +| LocalDataFlow.cs:157:33:157:40 | access to local variable nonSink0 | LocalDataFlow.cs:157:20:157:41 | [library code] call to method Insert | | LocalDataFlow.cs:158:15:158:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:195:39:195:46 | access to local variable nonSink0 | | LocalDataFlow.cs:158:15:158:22 | access to local variable nonSink0 | LocalDataFlow.cs:195:39:195:46 | access to local variable nonSink0 | | LocalDataFlow.cs:161:13:161:32 | SSA def(sink20) | LocalDataFlow.cs:162:15:162:20 | access to local variable sink20 | @@ -279,199 +320,262 @@ | LocalDataFlow.cs:179:20:179:36 | ... \|\| ... | LocalDataFlow.cs:179:9:179:36 | SSA def(nonSink7) | | LocalDataFlow.cs:179:32:179:36 | false | LocalDataFlow.cs:179:20:179:36 | ... \|\| ... | | LocalDataFlow.cs:183:13:183:42 | SSA def(sink26) | LocalDataFlow.cs:184:15:184:20 | access to local variable sink26 | +| LocalDataFlow.cs:183:22:183:42 | [library code] object creation of type Uri | LocalDataFlow.cs:183:22:183:42 | object creation of type Uri | | LocalDataFlow.cs:183:22:183:42 | object creation of type Uri | LocalDataFlow.cs:183:13:183:42 | SSA def(sink26) | -| LocalDataFlow.cs:183:37:183:41 | access to local variable sink9 | LocalDataFlow.cs:183:22:183:42 | object creation of type Uri | +| LocalDataFlow.cs:183:37:183:41 | access to local variable sink9 | LocalDataFlow.cs:183:22:183:42 | [library code] object creation of type Uri | | LocalDataFlow.cs:184:15:184:20 | [post] access to local variable sink26 | LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | | LocalDataFlow.cs:184:15:184:20 | access to local variable sink26 | LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | | LocalDataFlow.cs:185:13:185:38 | SSA def(sink27) | LocalDataFlow.cs:186:15:186:20 | access to local variable sink27 | | LocalDataFlow.cs:185:22:185:27 | [post] access to local variable sink26 | LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | -| LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | LocalDataFlow.cs:185:22:185:38 | call to method ToString | +| LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | LocalDataFlow.cs:185:22:185:38 | [library code] call to method ToString | | LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | +| LocalDataFlow.cs:185:22:185:38 | [library code] call to method ToString | LocalDataFlow.cs:185:22:185:38 | call to method ToString | | LocalDataFlow.cs:185:22:185:38 | call to method ToString | LocalDataFlow.cs:185:13:185:38 | SSA def(sink27) | | LocalDataFlow.cs:187:13:187:40 | SSA def(sink28) | LocalDataFlow.cs:188:15:188:20 | access to local variable sink28 | | LocalDataFlow.cs:187:22:187:27 | [post] access to local variable sink26 | LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | -| LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | LocalDataFlow.cs:187:22:187:40 | access to property PathAndQuery | +| LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | LocalDataFlow.cs:187:22:187:40 | [library code] access to property PathAndQuery | | LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | +| LocalDataFlow.cs:187:22:187:40 | [library code] access to property PathAndQuery | LocalDataFlow.cs:187:22:187:40 | access to property PathAndQuery | | LocalDataFlow.cs:187:22:187:40 | access to property PathAndQuery | LocalDataFlow.cs:187:13:187:40 | SSA def(sink28) | | LocalDataFlow.cs:189:13:189:33 | SSA def(sink29) | LocalDataFlow.cs:190:15:190:20 | access to local variable sink29 | | LocalDataFlow.cs:189:22:189:27 | [post] access to local variable sink26 | LocalDataFlow.cs:191:22:191:27 | access to local variable sink26 | -| LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | LocalDataFlow.cs:189:22:189:33 | access to property Query | +| LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | LocalDataFlow.cs:189:22:189:33 | [library code] access to property Query | | LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | LocalDataFlow.cs:191:22:191:27 | access to local variable sink26 | +| LocalDataFlow.cs:189:22:189:33 | [library code] access to property Query | LocalDataFlow.cs:189:22:189:33 | access to property Query | | LocalDataFlow.cs:189:22:189:33 | access to property Query | LocalDataFlow.cs:189:13:189:33 | SSA def(sink29) | | LocalDataFlow.cs:191:13:191:42 | SSA def(sink30) | LocalDataFlow.cs:192:15:192:20 | access to local variable sink30 | -| LocalDataFlow.cs:191:22:191:27 | access to local variable sink26 | LocalDataFlow.cs:191:22:191:42 | access to property OriginalString | +| LocalDataFlow.cs:191:22:191:27 | access to local variable sink26 | LocalDataFlow.cs:191:22:191:42 | [library code] access to property OriginalString | +| LocalDataFlow.cs:191:22:191:42 | [library code] access to property OriginalString | LocalDataFlow.cs:191:22:191:42 | access to property OriginalString | | LocalDataFlow.cs:191:22:191:42 | access to property OriginalString | LocalDataFlow.cs:191:13:191:42 | SSA def(sink30) | | LocalDataFlow.cs:192:15:192:20 | [post] access to local variable sink30 | LocalDataFlow.cs:207:49:207:54 | access to local variable sink30 | | LocalDataFlow.cs:192:15:192:20 | access to local variable sink30 | LocalDataFlow.cs:207:49:207:54 | access to local variable sink30 | | LocalDataFlow.cs:195:13:195:47 | SSA def(nonSink8) | LocalDataFlow.cs:196:15:196:22 | access to local variable nonSink8 | +| LocalDataFlow.cs:195:24:195:47 | [library code] object creation of type Uri | LocalDataFlow.cs:195:24:195:47 | object creation of type Uri | | LocalDataFlow.cs:195:24:195:47 | object creation of type Uri | LocalDataFlow.cs:195:13:195:47 | SSA def(nonSink8) | -| LocalDataFlow.cs:195:39:195:46 | access to local variable nonSink0 | LocalDataFlow.cs:195:24:195:47 | object creation of type Uri | +| LocalDataFlow.cs:195:39:195:46 | access to local variable nonSink0 | LocalDataFlow.cs:195:24:195:47 | [library code] object creation of type Uri | | LocalDataFlow.cs:196:15:196:22 | [post] access to local variable nonSink8 | LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | | LocalDataFlow.cs:196:15:196:22 | access to local variable nonSink8 | LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | | LocalDataFlow.cs:197:9:197:38 | SSA def(nonSink0) | LocalDataFlow.cs:198:15:198:22 | access to local variable nonSink0 | | LocalDataFlow.cs:197:20:197:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | LocalDataFlow.cs:197:20:197:38 | call to method ToString | +| LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | LocalDataFlow.cs:197:20:197:38 | [library code] call to method ToString | | LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:197:20:197:38 | [library code] call to method ToString | LocalDataFlow.cs:197:20:197:38 | call to method ToString | | LocalDataFlow.cs:197:20:197:38 | call to method ToString | LocalDataFlow.cs:197:9:197:38 | SSA def(nonSink0) | | LocalDataFlow.cs:199:9:199:40 | SSA def(nonSink0) | LocalDataFlow.cs:200:15:200:22 | access to local variable nonSink0 | | LocalDataFlow.cs:199:20:199:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | LocalDataFlow.cs:199:20:199:40 | access to property PathAndQuery | +| LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | LocalDataFlow.cs:199:20:199:40 | [library code] access to property PathAndQuery | | LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:199:20:199:40 | [library code] access to property PathAndQuery | LocalDataFlow.cs:199:20:199:40 | access to property PathAndQuery | | LocalDataFlow.cs:199:20:199:40 | access to property PathAndQuery | LocalDataFlow.cs:199:9:199:40 | SSA def(nonSink0) | | LocalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) | LocalDataFlow.cs:202:15:202:22 | access to local variable nonSink0 | | LocalDataFlow.cs:201:20:201:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:203:20:203:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | LocalDataFlow.cs:201:20:201:33 | access to property Query | +| LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | LocalDataFlow.cs:201:20:201:33 | [library code] access to property Query | | LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | LocalDataFlow.cs:203:20:203:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:201:20:201:33 | [library code] access to property Query | LocalDataFlow.cs:201:20:201:33 | access to property Query | | LocalDataFlow.cs:201:20:201:33 | access to property Query | LocalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) | | LocalDataFlow.cs:203:9:203:42 | SSA def(nonSink0) | LocalDataFlow.cs:204:15:204:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:203:20:203:27 | access to local variable nonSink8 | LocalDataFlow.cs:203:20:203:42 | access to property OriginalString | +| LocalDataFlow.cs:203:20:203:27 | access to local variable nonSink8 | LocalDataFlow.cs:203:20:203:42 | [library code] access to property OriginalString | +| LocalDataFlow.cs:203:20:203:42 | [library code] access to property OriginalString | LocalDataFlow.cs:203:20:203:42 | access to property OriginalString | | LocalDataFlow.cs:203:20:203:42 | access to property OriginalString | LocalDataFlow.cs:203:9:203:42 | SSA def(nonSink0) | | LocalDataFlow.cs:204:15:204:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:213:51:213:58 | access to local variable nonSink0 | | LocalDataFlow.cs:204:15:204:22 | access to local variable nonSink0 | LocalDataFlow.cs:213:51:213:58 | access to local variable nonSink0 | | LocalDataFlow.cs:207:13:207:55 | SSA def(sink31) | LocalDataFlow.cs:208:15:208:20 | access to local variable sink31 | +| LocalDataFlow.cs:207:22:207:55 | [library code] object creation of type StringReader | LocalDataFlow.cs:207:22:207:55 | object creation of type StringReader | | LocalDataFlow.cs:207:22:207:55 | object creation of type StringReader | LocalDataFlow.cs:207:13:207:55 | SSA def(sink31) | -| LocalDataFlow.cs:207:49:207:54 | access to local variable sink30 | LocalDataFlow.cs:207:22:207:55 | object creation of type StringReader | +| LocalDataFlow.cs:207:49:207:54 | access to local variable sink30 | LocalDataFlow.cs:207:22:207:55 | [library code] object creation of type StringReader | | LocalDataFlow.cs:208:15:208:20 | [post] access to local variable sink31 | LocalDataFlow.cs:209:22:209:27 | access to local variable sink31 | | LocalDataFlow.cs:208:15:208:20 | access to local variable sink31 | LocalDataFlow.cs:209:22:209:27 | access to local variable sink31 | | LocalDataFlow.cs:209:13:209:39 | SSA def(sink32) | LocalDataFlow.cs:210:15:210:20 | access to local variable sink32 | -| LocalDataFlow.cs:209:22:209:27 | access to local variable sink31 | LocalDataFlow.cs:209:22:209:39 | call to method ReadToEnd | +| LocalDataFlow.cs:209:22:209:27 | access to local variable sink31 | LocalDataFlow.cs:209:22:209:39 | [library code] call to method ReadToEnd | +| LocalDataFlow.cs:209:22:209:39 | [library code] call to method ReadToEnd | LocalDataFlow.cs:209:22:209:39 | call to method ReadToEnd | | LocalDataFlow.cs:209:22:209:39 | call to method ReadToEnd | LocalDataFlow.cs:209:13:209:39 | SSA def(sink32) | | LocalDataFlow.cs:210:15:210:20 | [post] access to local variable sink32 | LocalDataFlow.cs:219:30:219:35 | access to local variable sink32 | | LocalDataFlow.cs:210:15:210:20 | access to local variable sink32 | LocalDataFlow.cs:219:30:219:35 | access to local variable sink32 | | LocalDataFlow.cs:213:13:213:59 | SSA def(nonSink9) | LocalDataFlow.cs:214:15:214:22 | access to local variable nonSink9 | +| LocalDataFlow.cs:213:24:213:59 | [library code] object creation of type StringReader | LocalDataFlow.cs:213:24:213:59 | object creation of type StringReader | | LocalDataFlow.cs:213:24:213:59 | object creation of type StringReader | LocalDataFlow.cs:213:13:213:59 | SSA def(nonSink9) | -| LocalDataFlow.cs:213:51:213:58 | access to local variable nonSink0 | LocalDataFlow.cs:213:24:213:59 | object creation of type StringReader | +| LocalDataFlow.cs:213:51:213:58 | access to local variable nonSink0 | LocalDataFlow.cs:213:24:213:59 | [library code] object creation of type StringReader | | LocalDataFlow.cs:214:15:214:22 | [post] access to local variable nonSink9 | LocalDataFlow.cs:215:20:215:27 | access to local variable nonSink9 | | LocalDataFlow.cs:214:15:214:22 | access to local variable nonSink9 | LocalDataFlow.cs:215:20:215:27 | access to local variable nonSink9 | | LocalDataFlow.cs:215:9:215:39 | SSA def(nonSink0) | LocalDataFlow.cs:216:15:216:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:215:20:215:27 | access to local variable nonSink9 | LocalDataFlow.cs:215:20:215:39 | call to method ReadToEnd | +| LocalDataFlow.cs:215:20:215:27 | access to local variable nonSink9 | LocalDataFlow.cs:215:20:215:39 | [library code] call to method ReadToEnd | +| LocalDataFlow.cs:215:20:215:39 | [library code] call to method ReadToEnd | LocalDataFlow.cs:215:20:215:39 | call to method ReadToEnd | | LocalDataFlow.cs:215:20:215:39 | call to method ReadToEnd | LocalDataFlow.cs:215:9:215:39 | SSA def(nonSink0) | | LocalDataFlow.cs:216:15:216:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:225:28:225:35 | access to local variable nonSink0 | | LocalDataFlow.cs:216:15:216:22 | access to local variable nonSink0 | LocalDataFlow.cs:225:28:225:35 | access to local variable nonSink0 | | LocalDataFlow.cs:219:13:219:127 | SSA def(sink33) | LocalDataFlow.cs:220:15:220:20 | access to local variable sink33 | | LocalDataFlow.cs:219:22:219:127 | (...) ... | LocalDataFlow.cs:219:13:219:127 | SSA def(sink33) | -| LocalDataFlow.cs:219:30:219:35 | access to local variable sink32 | LocalDataFlow.cs:219:30:219:48 | call to method Substring | -| LocalDataFlow.cs:219:30:219:48 | call to method Substring | LocalDataFlow.cs:219:30:219:67 | call to method ToLowerInvariant | -| LocalDataFlow.cs:219:30:219:67 | call to method ToLowerInvariant | LocalDataFlow.cs:219:30:219:77 | call to method ToUpper | -| LocalDataFlow.cs:219:30:219:77 | call to method ToUpper | LocalDataFlow.cs:219:30:219:87 | call to method Trim | -| LocalDataFlow.cs:219:30:219:87 | call to method Trim | LocalDataFlow.cs:219:30:219:105 | call to method Replace | -| LocalDataFlow.cs:219:30:219:105 | call to method Replace | LocalDataFlow.cs:219:30:219:119 | call to method Insert | -| LocalDataFlow.cs:219:30:219:119 | call to method Insert | LocalDataFlow.cs:219:30:219:127 | call to method Clone | +| LocalDataFlow.cs:219:30:219:35 | access to local variable sink32 | LocalDataFlow.cs:219:30:219:48 | [library code] call to method Substring | +| LocalDataFlow.cs:219:30:219:48 | [library code] call to method Substring | LocalDataFlow.cs:219:30:219:48 | call to method Substring | +| LocalDataFlow.cs:219:30:219:48 | call to method Substring | LocalDataFlow.cs:219:30:219:67 | [library code] call to method ToLowerInvariant | +| LocalDataFlow.cs:219:30:219:67 | [library code] call to method ToLowerInvariant | LocalDataFlow.cs:219:30:219:67 | call to method ToLowerInvariant | +| LocalDataFlow.cs:219:30:219:67 | call to method ToLowerInvariant | LocalDataFlow.cs:219:30:219:77 | [library code] call to method ToUpper | +| LocalDataFlow.cs:219:30:219:77 | [library code] call to method ToUpper | LocalDataFlow.cs:219:30:219:77 | call to method ToUpper | +| LocalDataFlow.cs:219:30:219:77 | call to method ToUpper | LocalDataFlow.cs:219:30:219:87 | [library code] call to method Trim | +| LocalDataFlow.cs:219:30:219:87 | [library code] call to method Trim | LocalDataFlow.cs:219:30:219:87 | call to method Trim | +| LocalDataFlow.cs:219:30:219:87 | call to method Trim | LocalDataFlow.cs:219:30:219:105 | [library code] call to method Replace | +| LocalDataFlow.cs:219:30:219:105 | [library code] call to method Replace | LocalDataFlow.cs:219:30:219:105 | call to method Replace | +| LocalDataFlow.cs:219:30:219:105 | [library code] call to method Replace | LocalDataFlow.cs:219:30:219:105 | call to method Replace | +| LocalDataFlow.cs:219:30:219:105 | call to method Replace | LocalDataFlow.cs:219:30:219:119 | [library code] call to method Insert | +| LocalDataFlow.cs:219:30:219:119 | [library code] call to method Insert | LocalDataFlow.cs:219:30:219:119 | call to method Insert | +| LocalDataFlow.cs:219:30:219:119 | [library code] call to method Insert | LocalDataFlow.cs:219:30:219:119 | call to method Insert | +| LocalDataFlow.cs:219:30:219:119 | call to method Insert | LocalDataFlow.cs:219:30:219:127 | [library code] call to method Clone | +| LocalDataFlow.cs:219:30:219:119 | call to method Insert | LocalDataFlow.cs:219:30:219:127 | [library code] call to method Clone | +| LocalDataFlow.cs:219:30:219:127 | [library code] call to method Clone | LocalDataFlow.cs:219:30:219:127 | call to method Clone | +| LocalDataFlow.cs:219:30:219:127 | [library code] call to method Clone | LocalDataFlow.cs:219:30:219:127 | call to method Clone | | LocalDataFlow.cs:219:30:219:127 | call to method Clone | LocalDataFlow.cs:219:22:219:127 | (...) ... | -| LocalDataFlow.cs:219:102:219:104 | "b" | LocalDataFlow.cs:219:30:219:105 | call to method Replace | -| LocalDataFlow.cs:219:117:219:118 | "" | LocalDataFlow.cs:219:30:219:119 | call to method Insert | +| LocalDataFlow.cs:219:102:219:104 | "b" | LocalDataFlow.cs:219:30:219:105 | [library code] call to method Replace | +| LocalDataFlow.cs:219:117:219:118 | "" | LocalDataFlow.cs:219:30:219:119 | [library code] call to method Insert | | LocalDataFlow.cs:220:15:220:20 | [post] access to local variable sink33 | LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | | LocalDataFlow.cs:220:15:220:20 | access to local variable sink33 | LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | | LocalDataFlow.cs:221:13:221:63 | SSA def(sink48) | LocalDataFlow.cs:222:15:222:20 | access to local variable sink48 | | LocalDataFlow.cs:221:22:221:27 | [post] access to local variable sink33 | LocalDataFlow.cs:231:40:231:45 | access to local variable sink33 | -| LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | LocalDataFlow.cs:221:22:221:39 | call to method Normalize | +| LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | LocalDataFlow.cs:221:22:221:39 | [library code] call to method Normalize | | LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | LocalDataFlow.cs:231:40:231:45 | access to local variable sink33 | -| LocalDataFlow.cs:221:22:221:39 | call to method Normalize | LocalDataFlow.cs:221:22:221:52 | call to method Remove | -| LocalDataFlow.cs:221:22:221:52 | call to method Remove | LocalDataFlow.cs:221:22:221:63 | call to method Split | +| LocalDataFlow.cs:221:22:221:39 | [library code] call to method Normalize | LocalDataFlow.cs:221:22:221:39 | call to method Normalize | +| LocalDataFlow.cs:221:22:221:39 | call to method Normalize | LocalDataFlow.cs:221:22:221:52 | [library code] call to method Remove | +| LocalDataFlow.cs:221:22:221:52 | [library code] call to method Remove | LocalDataFlow.cs:221:22:221:52 | call to method Remove | +| LocalDataFlow.cs:221:22:221:52 | call to method Remove | LocalDataFlow.cs:221:22:221:63 | [library code] call to method Split | +| LocalDataFlow.cs:221:22:221:63 | [library code] call to method Split | LocalDataFlow.cs:221:22:221:63 | call to method Split | | LocalDataFlow.cs:221:22:221:63 | call to method Split | LocalDataFlow.cs:221:13:221:63 | SSA def(sink48) | | LocalDataFlow.cs:225:9:225:127 | SSA def(nonSink0) | LocalDataFlow.cs:226:15:226:22 | access to local variable nonSink0 | | LocalDataFlow.cs:225:20:225:127 | (...) ... | LocalDataFlow.cs:225:9:225:127 | SSA def(nonSink0) | -| LocalDataFlow.cs:225:28:225:35 | access to local variable nonSink0 | LocalDataFlow.cs:225:28:225:48 | call to method Substring | -| LocalDataFlow.cs:225:28:225:48 | call to method Substring | LocalDataFlow.cs:225:28:225:67 | call to method ToLowerInvariant | -| LocalDataFlow.cs:225:28:225:67 | call to method ToLowerInvariant | LocalDataFlow.cs:225:28:225:77 | call to method ToUpper | -| LocalDataFlow.cs:225:28:225:77 | call to method ToUpper | LocalDataFlow.cs:225:28:225:87 | call to method Trim | -| LocalDataFlow.cs:225:28:225:87 | call to method Trim | LocalDataFlow.cs:225:28:225:105 | call to method Replace | -| LocalDataFlow.cs:225:28:225:105 | call to method Replace | LocalDataFlow.cs:225:28:225:119 | call to method Insert | -| LocalDataFlow.cs:225:28:225:119 | call to method Insert | LocalDataFlow.cs:225:28:225:127 | call to method Clone | +| LocalDataFlow.cs:225:28:225:35 | access to local variable nonSink0 | LocalDataFlow.cs:225:28:225:48 | [library code] call to method Substring | +| LocalDataFlow.cs:225:28:225:48 | [library code] call to method Substring | LocalDataFlow.cs:225:28:225:48 | call to method Substring | +| LocalDataFlow.cs:225:28:225:48 | call to method Substring | LocalDataFlow.cs:225:28:225:67 | [library code] call to method ToLowerInvariant | +| LocalDataFlow.cs:225:28:225:67 | [library code] call to method ToLowerInvariant | LocalDataFlow.cs:225:28:225:67 | call to method ToLowerInvariant | +| LocalDataFlow.cs:225:28:225:67 | call to method ToLowerInvariant | LocalDataFlow.cs:225:28:225:77 | [library code] call to method ToUpper | +| LocalDataFlow.cs:225:28:225:77 | [library code] call to method ToUpper | LocalDataFlow.cs:225:28:225:77 | call to method ToUpper | +| LocalDataFlow.cs:225:28:225:77 | call to method ToUpper | LocalDataFlow.cs:225:28:225:87 | [library code] call to method Trim | +| LocalDataFlow.cs:225:28:225:87 | [library code] call to method Trim | LocalDataFlow.cs:225:28:225:87 | call to method Trim | +| LocalDataFlow.cs:225:28:225:87 | call to method Trim | LocalDataFlow.cs:225:28:225:105 | [library code] call to method Replace | +| LocalDataFlow.cs:225:28:225:105 | [library code] call to method Replace | LocalDataFlow.cs:225:28:225:105 | call to method Replace | +| LocalDataFlow.cs:225:28:225:105 | [library code] call to method Replace | LocalDataFlow.cs:225:28:225:105 | call to method Replace | +| LocalDataFlow.cs:225:28:225:105 | call to method Replace | LocalDataFlow.cs:225:28:225:119 | [library code] call to method Insert | +| LocalDataFlow.cs:225:28:225:119 | [library code] call to method Insert | LocalDataFlow.cs:225:28:225:119 | call to method Insert | +| LocalDataFlow.cs:225:28:225:119 | [library code] call to method Insert | LocalDataFlow.cs:225:28:225:119 | call to method Insert | +| LocalDataFlow.cs:225:28:225:119 | call to method Insert | LocalDataFlow.cs:225:28:225:127 | [library code] call to method Clone | +| LocalDataFlow.cs:225:28:225:119 | call to method Insert | LocalDataFlow.cs:225:28:225:127 | [library code] call to method Clone | +| LocalDataFlow.cs:225:28:225:127 | [library code] call to method Clone | LocalDataFlow.cs:225:28:225:127 | call to method Clone | +| LocalDataFlow.cs:225:28:225:127 | [library code] call to method Clone | LocalDataFlow.cs:225:28:225:127 | call to method Clone | | LocalDataFlow.cs:225:28:225:127 | call to method Clone | LocalDataFlow.cs:225:20:225:127 | (...) ... | -| LocalDataFlow.cs:225:102:225:104 | "b" | LocalDataFlow.cs:225:28:225:105 | call to method Replace | -| LocalDataFlow.cs:225:117:225:118 | "" | LocalDataFlow.cs:225:28:225:119 | call to method Insert | +| LocalDataFlow.cs:225:102:225:104 | "b" | LocalDataFlow.cs:225:28:225:105 | [library code] call to method Replace | +| LocalDataFlow.cs:225:117:225:118 | "" | LocalDataFlow.cs:225:28:225:119 | [library code] call to method Insert | | LocalDataFlow.cs:226:15:226:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | | LocalDataFlow.cs:226:15:226:22 | access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | | LocalDataFlow.cs:227:13:227:68 | SSA def(nonSink15) | LocalDataFlow.cs:228:15:228:23 | access to local variable nonSink15 | | LocalDataFlow.cs:227:25:227:32 | [post] access to local variable nonSink0 | LocalDataFlow.cs:240:43:240:50 | access to local variable nonSink0 | -| LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:44 | call to method Normalize | +| LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:44 | [library code] call to method Normalize | | LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | LocalDataFlow.cs:240:43:240:50 | access to local variable nonSink0 | -| LocalDataFlow.cs:227:25:227:44 | call to method Normalize | LocalDataFlow.cs:227:25:227:57 | call to method Remove | -| LocalDataFlow.cs:227:25:227:57 | call to method Remove | LocalDataFlow.cs:227:25:227:68 | call to method Split | +| LocalDataFlow.cs:227:25:227:44 | [library code] call to method Normalize | LocalDataFlow.cs:227:25:227:44 | call to method Normalize | +| LocalDataFlow.cs:227:25:227:44 | call to method Normalize | LocalDataFlow.cs:227:25:227:57 | [library code] call to method Remove | +| LocalDataFlow.cs:227:25:227:57 | [library code] call to method Remove | LocalDataFlow.cs:227:25:227:57 | call to method Remove | +| LocalDataFlow.cs:227:25:227:57 | call to method Remove | LocalDataFlow.cs:227:25:227:68 | [library code] call to method Split | +| LocalDataFlow.cs:227:25:227:68 | [library code] call to method Split | LocalDataFlow.cs:227:25:227:68 | call to method Split | | LocalDataFlow.cs:227:25:227:68 | call to method Split | LocalDataFlow.cs:227:13:227:68 | SSA def(nonSink15) | | LocalDataFlow.cs:231:13:231:46 | SSA def(sink34) | LocalDataFlow.cs:232:15:232:20 | access to local variable sink34 | +| LocalDataFlow.cs:231:22:231:46 | [library code] object creation of type StringBuilder | LocalDataFlow.cs:231:22:231:46 | object creation of type StringBuilder | | LocalDataFlow.cs:231:22:231:46 | object creation of type StringBuilder | LocalDataFlow.cs:231:13:231:46 | SSA def(sink34) | -| LocalDataFlow.cs:231:40:231:45 | access to local variable sink33 | LocalDataFlow.cs:231:22:231:46 | object creation of type StringBuilder | +| LocalDataFlow.cs:231:40:231:45 | access to local variable sink33 | LocalDataFlow.cs:231:22:231:46 | [library code] object creation of type StringBuilder | | LocalDataFlow.cs:232:15:232:20 | [post] access to local variable sink34 | LocalDataFlow.cs:233:22:233:27 | access to local variable sink34 | | LocalDataFlow.cs:232:15:232:20 | access to local variable sink34 | LocalDataFlow.cs:233:22:233:27 | access to local variable sink34 | | LocalDataFlow.cs:233:13:233:38 | SSA def(sink35) | LocalDataFlow.cs:234:15:234:20 | access to local variable sink35 | -| LocalDataFlow.cs:233:22:233:27 | access to local variable sink34 | LocalDataFlow.cs:233:22:233:38 | call to method ToString | +| LocalDataFlow.cs:233:22:233:27 | access to local variable sink34 | LocalDataFlow.cs:233:22:233:38 | [library code] call to method ToString | +| LocalDataFlow.cs:233:22:233:38 | [library code] call to method ToString | LocalDataFlow.cs:233:22:233:38 | call to method ToString | | LocalDataFlow.cs:233:22:233:38 | call to method ToString | LocalDataFlow.cs:233:13:233:38 | SSA def(sink35) | | LocalDataFlow.cs:234:15:234:20 | [post] access to local variable sink35 | LocalDataFlow.cs:236:27:236:32 | access to local variable sink35 | | LocalDataFlow.cs:234:15:234:20 | access to local variable sink35 | LocalDataFlow.cs:236:27:236:32 | access to local variable sink35 | | LocalDataFlow.cs:235:13:235:42 | SSA def(sink36) | LocalDataFlow.cs:236:9:236:14 | access to local variable sink36 | +| LocalDataFlow.cs:235:22:235:42 | [library code] object creation of type StringBuilder | LocalDataFlow.cs:235:22:235:42 | object creation of type StringBuilder | | LocalDataFlow.cs:235:22:235:42 | object creation of type StringBuilder | LocalDataFlow.cs:235:13:235:42 | SSA def(sink36) | -| LocalDataFlow.cs:235:40:235:41 | "" | LocalDataFlow.cs:235:22:235:42 | object creation of type StringBuilder | +| LocalDataFlow.cs:235:40:235:41 | "" | LocalDataFlow.cs:235:22:235:42 | [library code] object creation of type StringBuilder | | LocalDataFlow.cs:236:9:236:14 | [post] access to local variable sink36 | LocalDataFlow.cs:237:15:237:20 | access to local variable sink36 | | LocalDataFlow.cs:236:9:236:14 | access to local variable sink36 | LocalDataFlow.cs:237:15:237:20 | access to local variable sink36 | -| LocalDataFlow.cs:236:27:236:32 | access to local variable sink35 | LocalDataFlow.cs:236:9:236:14 | access to local variable sink36 | +| LocalDataFlow.cs:236:9:236:33 | [library code] call to method AppendLine | LocalDataFlow.cs:236:9:236:14 | access to local variable sink36 | +| LocalDataFlow.cs:236:27:236:32 | access to local variable sink35 | LocalDataFlow.cs:236:9:236:33 | [library code] call to method AppendLine | | LocalDataFlow.cs:240:13:240:51 | SSA def(nonSink10) | LocalDataFlow.cs:241:15:241:23 | access to local variable nonSink10 | +| LocalDataFlow.cs:240:25:240:51 | [library code] object creation of type StringBuilder | LocalDataFlow.cs:240:25:240:51 | object creation of type StringBuilder | | LocalDataFlow.cs:240:25:240:51 | object creation of type StringBuilder | LocalDataFlow.cs:240:13:240:51 | SSA def(nonSink10) | -| LocalDataFlow.cs:240:43:240:50 | access to local variable nonSink0 | LocalDataFlow.cs:240:25:240:51 | object creation of type StringBuilder | +| LocalDataFlow.cs:240:43:240:50 | access to local variable nonSink0 | LocalDataFlow.cs:240:25:240:51 | [library code] object creation of type StringBuilder | | LocalDataFlow.cs:241:15:241:23 | [post] access to local variable nonSink10 | LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | | LocalDataFlow.cs:241:15:241:23 | access to local variable nonSink10 | LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | | LocalDataFlow.cs:242:9:242:39 | SSA def(nonSink0) | LocalDataFlow.cs:243:15:243:22 | access to local variable nonSink0 | | LocalDataFlow.cs:242:20:242:28 | [post] access to local variable nonSink10 | LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | LocalDataFlow.cs:242:20:242:39 | call to method ToString | +| LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | LocalDataFlow.cs:242:20:242:39 | [library code] call to method ToString | | LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | +| LocalDataFlow.cs:242:20:242:39 | [library code] call to method ToString | LocalDataFlow.cs:242:20:242:39 | call to method ToString | | LocalDataFlow.cs:242:20:242:39 | call to method ToString | LocalDataFlow.cs:242:9:242:39 | SSA def(nonSink0) | | LocalDataFlow.cs:243:15:243:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:244:30:244:37 | access to local variable nonSink0 | | LocalDataFlow.cs:243:15:243:22 | access to local variable nonSink0 | LocalDataFlow.cs:244:30:244:37 | access to local variable nonSink0 | | LocalDataFlow.cs:244:9:244:17 | [post] access to local variable nonSink10 | LocalDataFlow.cs:245:15:245:23 | access to local variable nonSink10 | | LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | LocalDataFlow.cs:245:15:245:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:244:30:244:37 | access to local variable nonSink0 | LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | +| LocalDataFlow.cs:244:9:244:38 | [library code] call to method AppendLine | LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | +| LocalDataFlow.cs:244:30:244:37 | access to local variable nonSink0 | LocalDataFlow.cs:244:9:244:38 | [library code] call to method AppendLine | | LocalDataFlow.cs:248:13:248:52 | SSA def(taintedDataContract) | LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | | LocalDataFlow.cs:248:13:248:52 | SSA qualifier def(taintedDataContract.AList) | LocalDataFlow.cs:251:22:251:46 | access to property AList | | LocalDataFlow.cs:248:35:248:52 | object creation of type DataContract | LocalDataFlow.cs:248:13:248:52 | SSA def(taintedDataContract) | | LocalDataFlow.cs:249:13:249:48 | SSA def(sink53) | LocalDataFlow.cs:250:15:250:20 | access to local variable sink53 | | LocalDataFlow.cs:249:22:249:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | LocalDataFlow.cs:249:22:249:48 | [library code] access to property AString | | LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | LocalDataFlow.cs:249:22:249:48 | access to property AString | | LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:249:22:249:48 | [library code] access to property AString | LocalDataFlow.cs:249:22:249:48 | access to property AString | | LocalDataFlow.cs:249:22:249:48 | access to property AString | LocalDataFlow.cs:249:13:249:48 | SSA def(sink53) | | LocalDataFlow.cs:251:13:251:57 | SSA def(sink54) | LocalDataFlow.cs:252:15:252:20 | access to local variable sink54 | | LocalDataFlow.cs:251:22:251:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:46 | [library code] access to property AList | | LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:46 | access to property AList | | LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:251:22:251:46 | [library code] access to property AList | LocalDataFlow.cs:251:22:251:46 | access to property AList | | LocalDataFlow.cs:251:22:251:46 | [post] access to property AList | LocalDataFlow.cs:260:20:260:44 | access to property AList | | LocalDataFlow.cs:251:22:251:46 | access to property AList | LocalDataFlow.cs:251:22:251:49 | access to indexer | | LocalDataFlow.cs:251:22:251:46 | access to property AList | LocalDataFlow.cs:260:20:260:44 | access to property AList | +| LocalDataFlow.cs:251:22:251:49 | access to indexer | LocalDataFlow.cs:251:22:251:57 | [library code] access to property AString | | LocalDataFlow.cs:251:22:251:49 | access to indexer | LocalDataFlow.cs:251:22:251:57 | access to property AString | +| LocalDataFlow.cs:251:22:251:57 | [library code] access to property AString | LocalDataFlow.cs:251:22:251:57 | access to property AString | | LocalDataFlow.cs:251:22:251:57 | access to property AString | LocalDataFlow.cs:251:13:251:57 | SSA def(sink54) | | LocalDataFlow.cs:255:13:255:55 | SSA def(nonTaintedDataContract) | LocalDataFlow.cs:256:20:256:41 | access to local variable nonTaintedDataContract | | LocalDataFlow.cs:255:38:255:55 | object creation of type DataContract | LocalDataFlow.cs:255:13:255:55 | SSA def(nonTaintedDataContract) | | LocalDataFlow.cs:256:9:256:49 | SSA def(nonSink0) | LocalDataFlow.cs:257:15:257:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:256:20:256:41 | access to local variable nonTaintedDataContract | LocalDataFlow.cs:256:20:256:49 | [library code] access to property AString | | LocalDataFlow.cs:256:20:256:41 | access to local variable nonTaintedDataContract | LocalDataFlow.cs:256:20:256:49 | access to property AString | +| LocalDataFlow.cs:256:20:256:49 | [library code] access to property AString | LocalDataFlow.cs:256:20:256:49 | access to property AString | | LocalDataFlow.cs:256:20:256:49 | access to property AString | LocalDataFlow.cs:256:9:256:49 | SSA def(nonSink0) | | LocalDataFlow.cs:258:9:258:44 | SSA def(nonSink2) | LocalDataFlow.cs:259:15:259:22 | access to local variable nonSink2 | | LocalDataFlow.cs:258:20:258:38 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | | LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | | LocalDataFlow.cs:258:20:258:44 | access to property AnInt | LocalDataFlow.cs:258:9:258:44 | SSA def(nonSink2) | | LocalDataFlow.cs:260:9:260:53 | SSA def(nonSink2) | LocalDataFlow.cs:261:15:261:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:44 | [library code] access to property AList | | LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:44 | access to property AList | +| LocalDataFlow.cs:260:20:260:44 | [library code] access to property AList | LocalDataFlow.cs:260:20:260:44 | access to property AList | | LocalDataFlow.cs:260:20:260:44 | access to property AList | LocalDataFlow.cs:260:20:260:47 | access to indexer | | LocalDataFlow.cs:260:20:260:53 | access to property AnInt | LocalDataFlow.cs:260:9:260:53 | SSA def(nonSink2) | | LocalDataFlow.cs:264:17:264:37 | SSA def(taintedTextBox) | LocalDataFlow.cs:265:22:265:35 | access to local variable taintedTextBox | | LocalDataFlow.cs:264:34:264:37 | null | LocalDataFlow.cs:264:17:264:37 | SSA def(taintedTextBox) | | LocalDataFlow.cs:265:13:265:40 | SSA def(sink60) | LocalDataFlow.cs:266:15:266:20 | access to local variable sink60 | -| LocalDataFlow.cs:265:22:265:35 | access to local variable taintedTextBox | LocalDataFlow.cs:265:22:265:40 | access to property Text | +| LocalDataFlow.cs:265:22:265:35 | access to local variable taintedTextBox | LocalDataFlow.cs:265:22:265:40 | [library code] access to property Text | +| LocalDataFlow.cs:265:22:265:40 | [library code] access to property Text | LocalDataFlow.cs:265:22:265:40 | access to property Text | | LocalDataFlow.cs:265:22:265:40 | access to property Text | LocalDataFlow.cs:265:13:265:40 | SSA def(sink60) | | LocalDataFlow.cs:269:17:269:40 | SSA def(nonTaintedTextBox) | LocalDataFlow.cs:270:20:270:36 | access to local variable nonTaintedTextBox | | LocalDataFlow.cs:269:37:269:40 | null | LocalDataFlow.cs:269:17:269:40 | SSA def(nonTaintedTextBox) | | LocalDataFlow.cs:270:9:270:41 | SSA def(nonSink0) | LocalDataFlow.cs:271:15:271:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:270:20:270:36 | access to local variable nonTaintedTextBox | LocalDataFlow.cs:270:20:270:41 | access to property Text | +| LocalDataFlow.cs:270:20:270:36 | access to local variable nonTaintedTextBox | LocalDataFlow.cs:270:20:270:41 | [library code] access to property Text | +| LocalDataFlow.cs:270:20:270:41 | [library code] access to property Text | LocalDataFlow.cs:270:20:270:41 | access to property Text | | LocalDataFlow.cs:270:20:270:41 | access to property Text | LocalDataFlow.cs:270:9:270:41 | SSA def(nonSink0) | | LocalDataFlow.cs:274:13:274:51 | SSA def(sink67) | LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | +| LocalDataFlow.cs:274:22:274:51 | [library code] call to method Run | LocalDataFlow.cs:274:22:274:51 | call to method Run | | LocalDataFlow.cs:274:22:274:51 | call to method Run | LocalDataFlow.cs:274:13:274:51 | SSA def(sink67) | -| LocalDataFlow.cs:274:31:274:50 | [output] (...) => ... | LocalDataFlow.cs:274:22:274:51 | call to method Run | +| LocalDataFlow.cs:274:31:274:50 | [output] (...) => ... | LocalDataFlow.cs:274:22:274:51 | [library code] call to method Run | | LocalDataFlow.cs:275:15:275:20 | [post] access to local variable sink67 | LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | | LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | | LocalDataFlow.cs:276:13:276:33 | SSA def(sink68) | LocalDataFlow.cs:277:15:277:20 | access to local variable sink68 | | LocalDataFlow.cs:276:22:276:33 | await ... | LocalDataFlow.cs:276:13:276:33 | SSA def(sink68) | | LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | LocalDataFlow.cs:276:22:276:33 | await ... | | LocalDataFlow.cs:280:13:280:42 | SSA def(nonSink21) | LocalDataFlow.cs:281:15:281:23 | access to local variable nonSink21 | +| LocalDataFlow.cs:280:25:280:42 | [library code] call to method Run | LocalDataFlow.cs:280:25:280:42 | call to method Run | | LocalDataFlow.cs:280:25:280:42 | call to method Run | LocalDataFlow.cs:280:13:280:42 | SSA def(nonSink21) | -| LocalDataFlow.cs:280:34:280:41 | [output] (...) => ... | LocalDataFlow.cs:280:25:280:42 | call to method Run | +| LocalDataFlow.cs:280:34:280:41 | [output] (...) => ... | LocalDataFlow.cs:280:25:280:42 | [library code] call to method Run | | LocalDataFlow.cs:281:15:281:23 | [post] access to local variable nonSink21 | LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | | LocalDataFlow.cs:281:15:281:23 | access to local variable nonSink21 | LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | | LocalDataFlow.cs:282:9:282:34 | SSA def(nonSink0) | LocalDataFlow.cs:283:15:283:22 | access to local variable nonSink0 | @@ -525,28 +629,20 @@ | LocalDataFlow.cs:327:31:327:38 | access to local variable nonSink0 | LocalDataFlow.cs:327:22:327:38 | ... ?? ... | | LocalDataFlow.cs:347:28:347:30 | this | LocalDataFlow.cs:347:41:347:45 | this access | | LocalDataFlow.cs:347:50:347:52 | this | LocalDataFlow.cs:347:56:347:60 | this access | -| LocalDataFlow.cs:347:50:347:52 | value | LocalDataFlow.cs:347:50:347:52 | value | | LocalDataFlow.cs:347:50:347:52 | value | LocalDataFlow.cs:347:64:347:68 | access to parameter value | -| LocalDataFlow.cs:353:41:353:47 | tainted | LocalDataFlow.cs:353:41:353:47 | tainted | | LocalDataFlow.cs:353:41:353:47 | tainted | LocalDataFlow.cs:355:15:355:21 | access to parameter tainted | -| LocalDataFlow.cs:358:44:358:53 | nonTainted | LocalDataFlow.cs:358:44:358:53 | nonTainted | | LocalDataFlow.cs:358:44:358:53 | nonTainted | LocalDataFlow.cs:360:15:360:24 | access to parameter nonTainted | -| LocalDataFlow.cs:363:44:363:44 | x | LocalDataFlow.cs:363:44:363:44 | x | | LocalDataFlow.cs:363:44:363:44 | x | LocalDataFlow.cs:366:21:366:21 | access to parameter x | -| LocalDataFlow.cs:363:67:363:68 | os | LocalDataFlow.cs:363:67:363:68 | os | | LocalDataFlow.cs:363:67:363:68 | os | LocalDataFlow.cs:369:32:369:33 | access to parameter os | | LocalDataFlow.cs:366:21:366:21 | access to parameter x | LocalDataFlow.cs:366:16:366:21 | ... = ... | | LocalDataFlow.cs:369:32:369:33 | access to parameter os | LocalDataFlow.cs:369:26:369:33 | ... = ... | -| LocalDataFlow.cs:374:41:374:44 | args | LocalDataFlow.cs:374:41:374:44 | args | | LocalDataFlow.cs:374:41:374:44 | args | LocalDataFlow.cs:376:29:376:32 | access to parameter args | | LocalDataFlow.cs:376:29:376:32 | [post] access to parameter args | LocalDataFlow.cs:377:27:377:30 | access to parameter args | | LocalDataFlow.cs:376:29:376:32 | access to parameter args | LocalDataFlow.cs:376:29:376:32 | call to operator implicit conversion | | LocalDataFlow.cs:376:29:376:32 | access to parameter args | LocalDataFlow.cs:377:27:377:30 | access to parameter args | | SSA.cs:5:17:5:17 | SSA entry def(this.S) | SSA.cs:67:9:67:14 | access to field S | | SSA.cs:5:17:5:17 | this | SSA.cs:67:9:67:12 | this access | -| SSA.cs:5:26:5:32 | tainted | SSA.cs:5:26:5:32 | tainted | | SSA.cs:5:26:5:32 | tainted | SSA.cs:8:24:8:30 | access to parameter tainted | -| SSA.cs:5:42:5:51 | nonTainted | SSA.cs:5:42:5:51 | nonTainted | | SSA.cs:5:42:5:51 | nonTainted | SSA.cs:12:24:12:33 | access to parameter nonTainted | | SSA.cs:8:13:8:30 | SSA def(ssaSink0) | SSA.cs:9:15:9:22 | access to local variable ssaSink0 | | SSA.cs:8:24:8:30 | access to parameter tainted | SSA.cs:8:13:8:30 | SSA def(ssaSink0) | @@ -826,7 +922,6 @@ | SSA.cs:136:23:136:28 | SSA def(this.S) | SSA.cs:137:15:137:20 | access to field S | | SSA.cs:136:23:136:28 | SSA qualifier def(this.S.SsaFieldNonSink0) | SSA.cs:137:15:137:37 | access to field SsaFieldNonSink0 | | SSA.cs:136:23:136:28 | access to field S | SSA.cs:136:23:136:28 | SSA def(this.S) | -| SSA.cs:144:34:144:34 | t | SSA.cs:144:34:144:34 | t | | SSA.cs:144:34:144:34 | t | SSA.cs:146:13:146:13 | access to parameter t | | SSA.cs:146:13:146:13 | (...) ... | SSA.cs:146:13:146:21 | ... == ... | | SSA.cs:146:13:146:13 | access to parameter t | SSA.cs:146:13:146:13 | (...) ... | @@ -835,7 +930,6 @@ | SSA.cs:147:17:147:26 | default(...) | SSA.cs:147:13:147:26 | SSA def(t) | | SSA.cs:149:13:149:17 | SSA def(t) | SSA.cs:144:17:144:26 | SSA phi(t) | | SSA.cs:149:17:149:17 | access to parameter t | SSA.cs:149:13:149:17 | SSA def(t) | -| SSA.cs:152:36:152:36 | t | SSA.cs:152:36:152:36 | t | | SSA.cs:152:36:152:36 | t | SSA.cs:154:13:154:13 | access to parameter t | | SSA.cs:154:13:154:13 | (...) ... | SSA.cs:154:13:154:21 | ... == ... | | SSA.cs:154:13:154:13 | access to parameter t | SSA.cs:152:17:152:28 | SSA phi(t) | @@ -844,9 +938,7 @@ | SSA.cs:155:25:155:25 | SSA def(t) | SSA.cs:152:17:152:28 | SSA phi(t) | | SSA.cs:155:25:155:25 | access to parameter t | SSA.cs:152:17:152:28 | SSA phi(t) | | SSA.cs:166:10:166:13 | this | SSA.cs:166:19:166:22 | this access | -| SSA.cs:168:22:168:28 | tainted | SSA.cs:168:22:168:28 | tainted | | SSA.cs:168:22:168:28 | tainted | SSA.cs:173:24:173:30 | access to parameter tainted | -| SSA.cs:168:35:168:35 | i | SSA.cs:168:35:168:35 | i | | SSA.cs:168:35:168:35 | i | SSA.cs:171:13:171:13 | access to parameter i | | SSA.cs:170:16:170:28 | SSA def(ssaSink5) | SSA.cs:180:9:180:24 | SSA phi(ssaSink5) | | SSA.cs:170:27:170:28 | "" | SSA.cs:170:16:170:28 | SSA def(ssaSink5) | @@ -863,9 +955,7 @@ | SSA.cs:177:21:177:28 | access to local variable ssaSink5 | SSA.cs:176:21:176:28 | access to local variable ssaSink5 | | SSA.cs:177:21:177:28 | access to local variable ssaSink5 | SSA.cs:180:9:180:24 | SSA phi(ssaSink5) | | SSA.cs:180:9:180:24 | SSA phi(ssaSink5) | SSA.cs:180:15:180:22 | access to local variable ssaSink5 | -| Splitting.cs:3:18:3:18 | b | Splitting.cs:3:18:3:18 | b | | Splitting.cs:3:18:3:18 | b | Splitting.cs:6:13:6:13 | access to parameter b | -| Splitting.cs:3:28:3:34 | tainted | Splitting.cs:3:28:3:34 | tainted | | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:5:17:5:23 | access to parameter tainted | | Splitting.cs:5:13:5:23 | SSA def(x) | Splitting.cs:8:19:8:19 | [b (line 3): true] access to local variable x | | Splitting.cs:5:13:5:23 | SSA def(x) | Splitting.cs:12:15:12:15 | [b (line 3): false] access to local variable x | @@ -878,7 +968,6 @@ | Splitting.cs:9:17:9:17 | [b (line 3): true] access to local variable x | Splitting.cs:12:15:12:15 | [b (line 3): true] access to local variable x | | Splitting.cs:12:15:12:15 | [b (line 3): true] access to local variable x | Splitting.cs:14:19:14:19 | access to local variable x | | Splitting.cs:12:15:12:15 | [post] [b (line 3): true] access to local variable x | Splitting.cs:14:19:14:19 | access to local variable x | -| Splitting.cs:17:18:17:18 | b | Splitting.cs:17:18:17:18 | b | | Splitting.cs:17:18:17:18 | b | Splitting.cs:20:13:20:13 | access to parameter b | | Splitting.cs:19:13:19:18 | SSA def(x) | Splitting.cs:22:19:22:19 | [b (line 17): true] access to local variable x | | Splitting.cs:19:13:19:18 | SSA def(x) | Splitting.cs:25:15:25:15 | [b (line 17): false] access to local variable x | @@ -891,7 +980,6 @@ | Splitting.cs:25:15:25:15 | [b (line 17): true] access to local variable x | Splitting.cs:27:19:27:19 | access to local variable x | | Splitting.cs:25:15:25:15 | [post] [b (line 17): false] access to local variable x | Splitting.cs:29:19:29:19 | access to local variable x | | Splitting.cs:25:15:25:15 | [post] [b (line 17): true] access to local variable x | Splitting.cs:27:19:27:19 | access to local variable x | -| Splitting.cs:32:18:32:18 | b | Splitting.cs:32:18:32:18 | b | | Splitting.cs:32:18:32:18 | b | Splitting.cs:35:13:35:13 | access to parameter b | | Splitting.cs:35:13:35:13 | access to parameter b | Splitting.cs:39:15:39:15 | [b (line 32): false] access to parameter b | | Splitting.cs:35:13:35:13 | access to parameter b | Splitting.cs:39:15:39:15 | [b (line 32): true] access to parameter b | @@ -912,7 +1000,6 @@ | Splitting.cs:40:23:40:23 | [b (line 32): true] access to local variable x | Splitting.cs:40:15:40:23 | [b (line 32): true] (...) ... | | Splitting.cs:41:19:41:21 | [b (line 32): false] "d" | Splitting.cs:41:15:41:21 | [b (line 32): false] ... = ... | | Splitting.cs:41:19:41:21 | [b (line 32): true] "d" | Splitting.cs:41:15:41:21 | [b (line 32): true] ... = ... | -| Splitting.cs:46:18:46:18 | b | Splitting.cs:46:18:46:18 | b | | Splitting.cs:46:18:46:18 | b | Splitting.cs:49:13:49:13 | access to parameter b | | Splitting.cs:48:13:48:18 | SSA def(x) | Splitting.cs:53:13:53:13 | [b (line 46): false] access to local variable x | | Splitting.cs:48:17:48:18 | "" | Splitting.cs:48:13:48:18 | SSA def(x) | From 62e2ffe62346a01a4bf63eca9d0b747919f7738f Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 16 Apr 2020 17:19:12 +0200 Subject: [PATCH 0159/1298] C++: Make PartialDefinitionNode private and add/update comments based on review comments --- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 18 ++++++++++++++++-- .../dataflow/taint-tests/taint.cpp | 16 ++++++++-------- 2 files changed, 24 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 c5c994a8509..8b0ade838dd 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 @@ -251,7 +251,7 @@ abstract class PostUpdateNode extends InstructionNode { * setY(&x); // a partial definition of the object `x`. * ``` */ -abstract class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { } +abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { } private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { override ChiInstruction instr; @@ -264,7 +264,7 @@ 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 + // the total operand - so this definition gives consistency errors in // DataFlowImplConsistency::Consistency. However, it's not clear what (if any) implications // this consistency failure has. override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() } @@ -430,9 +430,23 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction // for now. iTo.getAnOperand().(ChiTotalOperand).getDef() = iFrom or + // The next two rules allow flow from partial definitions in setters to succeeding loads in the caller. + // First, we add flow from write side-effects to non-conflated chi instructions through their + // partial operands. Consider the following example: + // ``` + // void setX(Point* p, int new_x) { + // p->x = new_x; + // } + // ... + // setX(&p, taint()); + // ``` + // Here, a `WriteSideEffectInstruction` will provide a new definition for `p->x` after the call to + // `setX`, which will be melded into `p` through a chi instruction. iTo.getAnOperand().(ChiPartialOperand).getDef() = iFrom.(WriteSideEffectInstruction) and not iTo.isResultConflated() or + // Next, we add flow from non-conflated chi instructions to loads (even when they are not precise). + // This ensures that loads of `p->x` gets data flow from the `WriteSideEffectInstruction` above. exists(ChiInstruction chi | iFrom = chi | not chi.isResultConflated() and iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = chi 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 efcd600e21e..5d8327017fa 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); // [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] + 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); } // --- arrays --- From c705797a2dede130fd4fb83660f1d1c1b2908216 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Thu, 16 Apr 2020 11:58:09 -0400 Subject: [PATCH 0160/1298] C++: IR construction for `_Imaginary` types Includes a fairly exhaustive test case for arithmetic operations involving `_Complex` and/or `_Imaginary` types. Thanks to these new tests, I discovered that the extractor treats certain arithmetic operations on `_Imaginary` types as separate expression kinds, so I added support for those kinds in IR construction. --- .../raw/internal/TranslatedExpr.qll | 31 +- .../library-tests/ir/ir/PrintAST.expected | 1503 ++++++++++++++++- cpp/ql/test/library-tests/ir/ir/complex.c | 150 +- .../test/library-tests/ir/ir/raw_ir.expected | 601 ++++++- cpp/ql/test/library-tests/ir/types/complex.c | 13 +- 5 files changed, 2219 insertions(+), 79 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll index b8ede454ba2..c072aae1258 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -1100,13 +1100,36 @@ private Opcode binaryBitwiseOpcode(BinaryBitwiseOperation expr) { } private Opcode binaryArithmeticOpcode(BinaryArithmeticOperation expr) { - expr instanceof AddExpr and result instanceof Opcode::Add + ( + expr instanceof AddExpr + or + expr instanceof ImaginaryRealAddExpr + or + expr instanceof RealImaginaryAddExpr + ) and + result instanceof Opcode::Add or - expr instanceof SubExpr and result instanceof Opcode::Sub + ( + expr instanceof SubExpr + or + expr instanceof ImaginaryRealSubExpr + or + expr instanceof RealImaginarySubExpr + ) and + result instanceof Opcode::Sub or - expr instanceof MulExpr and result instanceof Opcode::Mul + ( + expr instanceof MulExpr + or + expr instanceof ImaginaryMulExpr + ) and + result instanceof Opcode::Mul or - expr instanceof DivExpr and result instanceof Opcode::Div + ( + expr instanceof DivExpr or + expr instanceof ImaginaryDivExpr + ) and + result instanceof Opcode::Div or expr instanceof RemExpr and result instanceof Opcode::Rem or diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected index 2ff49047c8d..24b09161af3 100644 --- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected +++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected @@ -235,7 +235,7 @@ clang.cpp: # 6| Type = [IntType] int # 6| ValueCategory = lvalue complex.c: -# 1| [TopLevelFunction] void complex_math() +# 1| [TopLevelFunction] void complex_literals() # 1| params: # 1| body: [Block] { ... } # 2| 0: [DeclStmt] declaration @@ -246,50 +246,1475 @@ complex.c: # 2| Conversion = [FloatingPointConversion] floating point conversion # 2| Type = [ArithmeticType] _Complex float # 2| ValueCategory = prvalue -# 2| expr: [AddExpr] ... + ... -# 2| Type = [ArithmeticType] _Complex double +# 2| expr: [Literal] 2.0 +# 2| Type = [DoubleType] double +# 2| Value = [Literal] 2.0 # 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| 1: [ExprStmt] ExprStmt +# 3| 0: [AssignExpr] ... = ... # 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 = lvalue +# 3| 1: [CStyleCast] (_Complex float)... +# 3| Conversion = [FloatingPointConversion] floating point conversion +# 3| Type = [ArithmeticType] _Complex float +# 3| ValueCategory = prvalue +# 3| expr: [Literal] 1.0i +# 3| Type = [ArithmeticType] _Imaginary float +# 3| Value = [Literal] 1.0i # 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| 0: [VariableDeclarationEntry] definition of cd +# 4| Type = [ArithmeticType] _Complex double +# 4| init: [Initializer] initializer for cd +# 4| expr: [CStyleCast] (_Complex double)... # 4| Conversion = [FloatingPointConversion] floating point conversion -# 4| Type = [DoubleType] double +# 4| Type = [ArithmeticType] _Complex double # 4| ValueCategory = prvalue -# 4| expr: [VariableAccess] cf2 -# 4| Type = [ArithmeticType] _Complex float -# 4| ValueCategory = prvalue(load) -# 5| 3: [ReturnStmt] return ... +# 4| expr: [Literal] 3.0 +# 4| Type = [DoubleType] double +# 4| Value = [Literal] 3.0 +# 4| ValueCategory = prvalue +# 5| 3: [ExprStmt] ExprStmt +# 5| 0: [AssignExpr] ... = ... +# 5| Type = [ArithmeticType] _Complex double +# 5| ValueCategory = prvalue +# 5| 0: [VariableAccess] cd +# 5| Type = [ArithmeticType] _Complex double +# 5| ValueCategory = lvalue +# 5| 1: [CStyleCast] (_Complex double)... +# 5| Conversion = [FloatingPointConversion] floating point conversion +# 5| Type = [ArithmeticType] _Complex double +# 5| ValueCategory = prvalue +# 5| expr: [Literal] 1.0i +# 5| Type = [ArithmeticType] _Imaginary float +# 5| Value = [Literal] 1.0i +# 5| ValueCategory = prvalue +# 6| 4: [DeclStmt] declaration +# 6| 0: [VariableDeclarationEntry] definition of cld +# 6| Type = [ArithmeticType] _Complex long double +# 6| init: [Initializer] initializer for cld +# 6| expr: [CStyleCast] (_Complex long double)... +# 6| Conversion = [FloatingPointConversion] floating point conversion +# 6| Type = [ArithmeticType] _Complex long double +# 6| ValueCategory = prvalue +# 6| expr: [Literal] 5.0 +# 6| Type = [DoubleType] double +# 6| Value = [Literal] 5.0 +# 6| ValueCategory = prvalue +# 7| 5: [ExprStmt] ExprStmt +# 7| 0: [AssignExpr] ... = ... +# 7| Type = [ArithmeticType] _Complex long double +# 7| ValueCategory = prvalue +# 7| 0: [VariableAccess] cld +# 7| Type = [ArithmeticType] _Complex long double +# 7| ValueCategory = lvalue +# 7| 1: [CStyleCast] (_Complex long double)... +# 7| Conversion = [FloatingPointConversion] floating point conversion +# 7| Type = [ArithmeticType] _Complex long double +# 7| ValueCategory = prvalue +# 7| expr: [Literal] 1.0i +# 7| Type = [ArithmeticType] _Imaginary float +# 7| Value = [Literal] 1.0i +# 7| ValueCategory = prvalue +# 9| 6: [DeclStmt] declaration +# 9| 0: [VariableDeclarationEntry] definition of jf +# 9| Type = [ArithmeticType] _Imaginary float +# 9| init: [Initializer] initializer for jf +# 9| expr: [Literal] 1.0i +# 9| Type = [ArithmeticType] _Imaginary float +# 9| Value = [Literal] 1.0i +# 9| ValueCategory = prvalue +# 10| 7: [DeclStmt] declaration +# 10| 0: [VariableDeclarationEntry] definition of jd +# 10| Type = [ArithmeticType] _Imaginary double +# 10| init: [Initializer] initializer for jd +# 10| expr: [CStyleCast] (_Imaginary double)... +# 10| Conversion = [FloatingPointConversion] floating point conversion +# 10| Type = [ArithmeticType] _Imaginary double +# 10| ValueCategory = prvalue +# 10| expr: [Literal] 1.0i +# 10| Type = [ArithmeticType] _Imaginary float +# 10| Value = [Literal] 1.0i +# 10| ValueCategory = prvalue +# 11| 8: [DeclStmt] declaration +# 11| 0: [VariableDeclarationEntry] definition of jld +# 11| Type = [ArithmeticType] _Imaginary long double +# 11| init: [Initializer] initializer for jld +# 11| expr: [CStyleCast] (_Imaginary long double)... +# 11| Conversion = [FloatingPointConversion] floating point conversion +# 11| Type = [ArithmeticType] _Imaginary long double +# 11| ValueCategory = prvalue +# 11| expr: [Literal] 1.0i +# 11| Type = [ArithmeticType] _Imaginary float +# 11| Value = [Literal] 1.0i +# 11| ValueCategory = prvalue +# 12| 9: [ReturnStmt] return ... +# 14| [TopLevelFunction] void complex_arithmetic() +# 14| params: +# 14| body: [Block] { ... } +# 15| 0: [DeclStmt] declaration +# 15| 0: [VariableDeclarationEntry] definition of f1 +# 15| Type = [FloatType] float +# 15| init: [Initializer] initializer for f1 +# 15| expr: [CStyleCast] (float)... +# 15| Conversion = [FloatingPointConversion] floating point conversion +# 15| Type = [FloatType] float +# 15| Value = [CStyleCast] 5.0 +# 15| ValueCategory = prvalue +# 15| expr: [Literal] 5.0 +# 15| Type = [DoubleType] double +# 15| Value = [Literal] 5.0 +# 15| ValueCategory = prvalue +# 16| 1: [DeclStmt] declaration +# 16| 0: [VariableDeclarationEntry] definition of f2 +# 16| Type = [FloatType] float +# 16| init: [Initializer] initializer for f2 +# 16| expr: [CStyleCast] (float)... +# 16| Conversion = [FloatingPointConversion] floating point conversion +# 16| Type = [FloatType] float +# 16| Value = [CStyleCast] 7.0 +# 16| ValueCategory = prvalue +# 16| expr: [Literal] 7.0 +# 16| Type = [DoubleType] double +# 16| Value = [Literal] 7.0 +# 16| ValueCategory = prvalue +# 17| 2: [DeclStmt] declaration +# 17| 0: [VariableDeclarationEntry] definition of f3 +# 17| Type = [FloatType] float +# 18| 3: [DeclStmt] declaration +# 18| 0: [VariableDeclarationEntry] definition of cf1 +# 18| Type = [ArithmeticType] _Complex float +# 18| init: [Initializer] initializer for cf1 +# 18| expr: [CStyleCast] (_Complex float)... +# 18| Conversion = [FloatingPointConversion] floating point conversion +# 18| Type = [ArithmeticType] _Complex float +# 18| ValueCategory = prvalue +# 18| expr: [Literal] 2.0 +# 18| Type = [DoubleType] double +# 18| Value = [Literal] 2.0 +# 18| ValueCategory = prvalue +# 19| 4: [DeclStmt] declaration +# 19| 0: [VariableDeclarationEntry] definition of cf2 +# 19| Type = [ArithmeticType] _Complex float +# 19| init: [Initializer] initializer for cf2 +# 19| expr: [CStyleCast] (_Complex float)... +# 19| Conversion = [FloatingPointConversion] floating point conversion +# 19| Type = [ArithmeticType] _Complex float +# 19| ValueCategory = prvalue +# 19| expr: [Literal] 1.0i +# 19| Type = [ArithmeticType] _Imaginary float +# 19| Value = [Literal] 1.0i +# 19| ValueCategory = prvalue +# 20| 5: [DeclStmt] declaration +# 20| 0: [VariableDeclarationEntry] definition of cf3 +# 20| Type = [ArithmeticType] _Complex float +# 21| 6: [DeclStmt] declaration +# 21| 0: [VariableDeclarationEntry] definition of jf1 +# 21| Type = [ArithmeticType] _Imaginary float +# 21| init: [Initializer] initializer for jf1 +# 21| expr: [Literal] 1.0i +# 21| Type = [ArithmeticType] _Imaginary float +# 21| Value = [Literal] 1.0i +# 21| ValueCategory = prvalue +# 22| 7: [DeclStmt] declaration +# 22| 0: [VariableDeclarationEntry] definition of jf2 +# 22| Type = [ArithmeticType] _Imaginary float +# 22| init: [Initializer] initializer for jf2 +# 22| expr: [Literal] 1.0i +# 22| Type = [ArithmeticType] _Imaginary float +# 22| Value = [Literal] 1.0i +# 22| ValueCategory = prvalue +# 23| 8: [DeclStmt] declaration +# 23| 0: [VariableDeclarationEntry] definition of jf3 +# 23| Type = [ArithmeticType] _Imaginary float +# 26| 9: [ExprStmt] ExprStmt +# 26| 0: [AssignExpr] ... = ... +# 26| Type = [ArithmeticType] _Complex float +# 26| ValueCategory = prvalue +# 26| 0: [VariableAccess] cf3 +# 26| Type = [ArithmeticType] _Complex float +# 26| ValueCategory = lvalue +# 26| 1: [UnaryPlusExpr] + ... +# 26| Type = [ArithmeticType] _Complex float +# 26| ValueCategory = prvalue +# 26| 0: [VariableAccess] cf1 +# 26| Type = [ArithmeticType] _Complex float +# 26| ValueCategory = prvalue(load) +# 27| 10: [ExprStmt] ExprStmt +# 27| 0: [AssignExpr] ... = ... +# 27| Type = [ArithmeticType] _Complex float +# 27| ValueCategory = prvalue +# 27| 0: [VariableAccess] cf3 +# 27| Type = [ArithmeticType] _Complex float +# 27| ValueCategory = lvalue +# 27| 1: [UnaryMinusExpr] - ... +# 27| Type = [ArithmeticType] _Complex float +# 27| ValueCategory = prvalue +# 27| 0: [VariableAccess] cf1 +# 27| Type = [ArithmeticType] _Complex float +# 27| ValueCategory = prvalue(load) +# 30| 11: [ExprStmt] ExprStmt +# 30| 0: [AssignExpr] ... = ... +# 30| Type = [ArithmeticType] _Complex float +# 30| ValueCategory = prvalue +# 30| 0: [VariableAccess] cf3 +# 30| Type = [ArithmeticType] _Complex float +# 30| ValueCategory = lvalue +# 30| 1: [AddExpr] ... + ... +# 30| Type = [ArithmeticType] _Complex float +# 30| ValueCategory = prvalue +# 30| 0: [VariableAccess] cf1 +# 30| Type = [ArithmeticType] _Complex float +# 30| ValueCategory = prvalue(load) +# 30| 1: [VariableAccess] cf2 +# 30| Type = [ArithmeticType] _Complex float +# 30| ValueCategory = prvalue(load) +# 31| 12: [ExprStmt] ExprStmt +# 31| 0: [AssignExpr] ... = ... +# 31| Type = [ArithmeticType] _Complex float +# 31| ValueCategory = prvalue +# 31| 0: [VariableAccess] cf3 +# 31| Type = [ArithmeticType] _Complex float +# 31| ValueCategory = lvalue +# 31| 1: [SubExpr] ... - ... +# 31| Type = [ArithmeticType] _Complex float +# 31| ValueCategory = prvalue +# 31| 0: [VariableAccess] cf1 +# 31| Type = [ArithmeticType] _Complex float +# 31| ValueCategory = prvalue(load) +# 31| 1: [VariableAccess] cf2 +# 31| Type = [ArithmeticType] _Complex float +# 31| ValueCategory = prvalue(load) +# 32| 13: [ExprStmt] ExprStmt +# 32| 0: [AssignExpr] ... = ... +# 32| Type = [ArithmeticType] _Complex float +# 32| ValueCategory = prvalue +# 32| 0: [VariableAccess] cf3 +# 32| Type = [ArithmeticType] _Complex float +# 32| ValueCategory = lvalue +# 32| 1: [MulExpr] ... * ... +# 32| Type = [ArithmeticType] _Complex float +# 32| ValueCategory = prvalue +# 32| 0: [VariableAccess] cf1 +# 32| Type = [ArithmeticType] _Complex float +# 32| ValueCategory = prvalue(load) +# 32| 1: [VariableAccess] cf2 +# 32| Type = [ArithmeticType] _Complex float +# 32| ValueCategory = prvalue(load) +# 33| 14: [ExprStmt] ExprStmt +# 33| 0: [AssignExpr] ... = ... +# 33| Type = [ArithmeticType] _Complex float +# 33| ValueCategory = prvalue +# 33| 0: [VariableAccess] cf3 +# 33| Type = [ArithmeticType] _Complex float +# 33| ValueCategory = lvalue +# 33| 1: [DivExpr] ... / ... +# 33| Type = [ArithmeticType] _Complex float +# 33| ValueCategory = prvalue +# 33| 0: [VariableAccess] cf1 +# 33| Type = [ArithmeticType] _Complex float +# 33| ValueCategory = prvalue(load) +# 33| 1: [VariableAccess] cf2 +# 33| Type = [ArithmeticType] _Complex float +# 33| ValueCategory = prvalue(load) +# 36| 15: [ExprStmt] ExprStmt +# 36| 0: [AssignExpr] ... = ... +# 36| Type = [ArithmeticType] _Imaginary float +# 36| ValueCategory = prvalue +# 36| 0: [VariableAccess] jf3 +# 36| Type = [ArithmeticType] _Imaginary float +# 36| ValueCategory = lvalue +# 36| 1: [UnaryPlusExpr] + ... +# 36| Type = [ArithmeticType] _Imaginary float +# 36| ValueCategory = prvalue +# 36| 0: [VariableAccess] jf1 +# 36| Type = [ArithmeticType] _Imaginary float +# 36| ValueCategory = prvalue(load) +# 37| 16: [ExprStmt] ExprStmt +# 37| 0: [AssignExpr] ... = ... +# 37| Type = [ArithmeticType] _Imaginary float +# 37| ValueCategory = prvalue +# 37| 0: [VariableAccess] jf3 +# 37| Type = [ArithmeticType] _Imaginary float +# 37| ValueCategory = lvalue +# 37| 1: [UnaryMinusExpr] - ... +# 37| Type = [ArithmeticType] _Imaginary float +# 37| ValueCategory = prvalue +# 37| 0: [VariableAccess] jf1 +# 37| Type = [ArithmeticType] _Imaginary float +# 37| ValueCategory = prvalue(load) +# 40| 17: [ExprStmt] ExprStmt +# 40| 0: [AssignExpr] ... = ... +# 40| Type = [ArithmeticType] _Imaginary float +# 40| ValueCategory = prvalue +# 40| 0: [VariableAccess] jf3 +# 40| Type = [ArithmeticType] _Imaginary float +# 40| ValueCategory = lvalue +# 40| 1: [AddExpr] ... + ... +# 40| Type = [ArithmeticType] _Imaginary float +# 40| ValueCategory = prvalue +# 40| 0: [VariableAccess] jf1 +# 40| Type = [ArithmeticType] _Imaginary float +# 40| ValueCategory = prvalue(load) +# 40| 1: [VariableAccess] jf2 +# 40| Type = [ArithmeticType] _Imaginary float +# 40| ValueCategory = prvalue(load) +# 41| 18: [ExprStmt] ExprStmt +# 41| 0: [AssignExpr] ... = ... +# 41| Type = [ArithmeticType] _Imaginary float +# 41| ValueCategory = prvalue +# 41| 0: [VariableAccess] jf3 +# 41| Type = [ArithmeticType] _Imaginary float +# 41| ValueCategory = lvalue +# 41| 1: [SubExpr] ... - ... +# 41| Type = [ArithmeticType] _Imaginary float +# 41| ValueCategory = prvalue +# 41| 0: [VariableAccess] jf1 +# 41| Type = [ArithmeticType] _Imaginary float +# 41| ValueCategory = prvalue(load) +# 41| 1: [VariableAccess] jf2 +# 41| Type = [ArithmeticType] _Imaginary float +# 41| ValueCategory = prvalue(load) +# 42| 19: [ExprStmt] ExprStmt +# 42| 0: [AssignExpr] ... = ... +# 42| Type = [FloatType] float +# 42| ValueCategory = prvalue +# 42| 0: [VariableAccess] f3 +# 42| Type = [FloatType] float +# 42| ValueCategory = lvalue +# 42| 1: [ImaginaryMulExpr] ... * ... +# 42| Type = [FloatType] float +# 42| ValueCategory = prvalue +# 42| 0: [VariableAccess] jf1 +# 42| Type = [ArithmeticType] _Imaginary float +# 42| ValueCategory = prvalue(load) +# 42| 1: [VariableAccess] jf2 +# 42| Type = [ArithmeticType] _Imaginary float +# 42| ValueCategory = prvalue(load) +# 43| 20: [ExprStmt] ExprStmt +# 43| 0: [AssignExpr] ... = ... +# 43| Type = [FloatType] float +# 43| ValueCategory = prvalue +# 43| 0: [VariableAccess] f3 +# 43| Type = [FloatType] float +# 43| ValueCategory = lvalue +# 43| 1: [DivExpr] ... / ... +# 43| Type = [FloatType] float +# 43| ValueCategory = prvalue +# 43| 0: [VariableAccess] jf1 +# 43| Type = [ArithmeticType] _Imaginary float +# 43| ValueCategory = prvalue(load) +# 43| 1: [VariableAccess] jf2 +# 43| Type = [ArithmeticType] _Imaginary float +# 43| ValueCategory = prvalue(load) +# 46| 21: [ExprStmt] ExprStmt +# 46| 0: [AssignExpr] ... = ... +# 46| Type = [ArithmeticType] _Complex float +# 46| ValueCategory = prvalue +# 46| 0: [VariableAccess] cf3 +# 46| Type = [ArithmeticType] _Complex float +# 46| ValueCategory = lvalue +# 46| 1: [ImaginaryRealAddExpr] ... + ... +# 46| Type = [ArithmeticType] _Complex float +# 46| ValueCategory = prvalue +# 46| 0: [VariableAccess] jf1 +# 46| Type = [ArithmeticType] _Imaginary float +# 46| ValueCategory = prvalue(load) +# 46| 1: [VariableAccess] f2 +# 46| Type = [FloatType] float +# 46| ValueCategory = prvalue(load) +# 47| 22: [ExprStmt] ExprStmt +# 47| 0: [AssignExpr] ... = ... +# 47| Type = [ArithmeticType] _Complex float +# 47| ValueCategory = prvalue +# 47| 0: [VariableAccess] cf3 +# 47| Type = [ArithmeticType] _Complex float +# 47| ValueCategory = lvalue +# 47| 1: [ImaginaryRealSubExpr] ... - ... +# 47| Type = [ArithmeticType] _Complex float +# 47| ValueCategory = prvalue +# 47| 0: [VariableAccess] jf1 +# 47| Type = [ArithmeticType] _Imaginary float +# 47| ValueCategory = prvalue(load) +# 47| 1: [VariableAccess] f2 +# 47| Type = [FloatType] float +# 47| ValueCategory = prvalue(load) +# 48| 23: [ExprStmt] ExprStmt +# 48| 0: [AssignExpr] ... = ... +# 48| Type = [ArithmeticType] _Imaginary float +# 48| ValueCategory = prvalue +# 48| 0: [VariableAccess] jf3 +# 48| Type = [ArithmeticType] _Imaginary float +# 48| ValueCategory = lvalue +# 48| 1: [MulExpr] ... * ... +# 48| Type = [ArithmeticType] _Imaginary float +# 48| ValueCategory = prvalue +# 48| 0: [VariableAccess] jf1 +# 48| Type = [ArithmeticType] _Imaginary float +# 48| ValueCategory = prvalue(load) +# 48| 1: [VariableAccess] f2 +# 48| Type = [FloatType] float +# 48| ValueCategory = prvalue(load) +# 49| 24: [ExprStmt] ExprStmt +# 49| 0: [AssignExpr] ... = ... +# 49| Type = [ArithmeticType] _Imaginary float +# 49| ValueCategory = prvalue +# 49| 0: [VariableAccess] jf3 +# 49| Type = [ArithmeticType] _Imaginary float +# 49| ValueCategory = lvalue +# 49| 1: [DivExpr] ... / ... +# 49| Type = [ArithmeticType] _Imaginary float +# 49| ValueCategory = prvalue +# 49| 0: [VariableAccess] jf1 +# 49| Type = [ArithmeticType] _Imaginary float +# 49| ValueCategory = prvalue(load) +# 49| 1: [VariableAccess] f2 +# 49| Type = [FloatType] float +# 49| ValueCategory = prvalue(load) +# 52| 25: [ExprStmt] ExprStmt +# 52| 0: [AssignExpr] ... = ... +# 52| Type = [ArithmeticType] _Complex float +# 52| ValueCategory = prvalue +# 52| 0: [VariableAccess] cf3 +# 52| Type = [ArithmeticType] _Complex float +# 52| ValueCategory = lvalue +# 52| 1: [RealImaginaryAddExpr] ... + ... +# 52| Type = [ArithmeticType] _Complex float +# 52| ValueCategory = prvalue +# 52| 0: [VariableAccess] f1 +# 52| Type = [FloatType] float +# 52| ValueCategory = prvalue(load) +# 52| 1: [VariableAccess] jf2 +# 52| Type = [ArithmeticType] _Imaginary float +# 52| ValueCategory = prvalue(load) +# 53| 26: [ExprStmt] ExprStmt +# 53| 0: [AssignExpr] ... = ... +# 53| Type = [ArithmeticType] _Complex float +# 53| ValueCategory = prvalue +# 53| 0: [VariableAccess] cf3 +# 53| Type = [ArithmeticType] _Complex float +# 53| ValueCategory = lvalue +# 53| 1: [RealImaginarySubExpr] ... - ... +# 53| Type = [ArithmeticType] _Complex float +# 53| ValueCategory = prvalue +# 53| 0: [VariableAccess] f1 +# 53| Type = [FloatType] float +# 53| ValueCategory = prvalue(load) +# 53| 1: [VariableAccess] jf2 +# 53| Type = [ArithmeticType] _Imaginary float +# 53| ValueCategory = prvalue(load) +# 54| 27: [ExprStmt] ExprStmt +# 54| 0: [AssignExpr] ... = ... +# 54| Type = [ArithmeticType] _Imaginary float +# 54| ValueCategory = prvalue +# 54| 0: [VariableAccess] jf3 +# 54| Type = [ArithmeticType] _Imaginary float +# 54| ValueCategory = lvalue +# 54| 1: [MulExpr] ... * ... +# 54| Type = [ArithmeticType] _Imaginary float +# 54| ValueCategory = prvalue +# 54| 0: [VariableAccess] f1 +# 54| Type = [FloatType] float +# 54| ValueCategory = prvalue(load) +# 54| 1: [VariableAccess] jf2 +# 54| Type = [ArithmeticType] _Imaginary float +# 54| ValueCategory = prvalue(load) +# 55| 28: [ExprStmt] ExprStmt +# 55| 0: [AssignExpr] ... = ... +# 55| Type = [ArithmeticType] _Imaginary float +# 55| ValueCategory = prvalue +# 55| 0: [VariableAccess] jf3 +# 55| Type = [ArithmeticType] _Imaginary float +# 55| ValueCategory = lvalue +# 55| 1: [ImaginaryDivExpr] ... / ... +# 55| Type = [ArithmeticType] _Imaginary float +# 55| ValueCategory = prvalue +# 55| 0: [VariableAccess] f1 +# 55| Type = [FloatType] float +# 55| ValueCategory = prvalue(load) +# 55| 1: [VariableAccess] jf2 +# 55| Type = [ArithmeticType] _Imaginary float +# 55| ValueCategory = prvalue(load) +# 56| 29: [ReturnStmt] return ... +# 58| [TopLevelFunction] void complex_conversions() +# 58| params: +# 58| body: [Block] { ... } +# 59| 0: [DeclStmt] declaration +# 59| 0: [VariableDeclarationEntry] definition of f +# 59| Type = [FloatType] float +# 59| init: [Initializer] initializer for f +# 59| expr: [CStyleCast] (float)... +# 59| Conversion = [FloatingPointConversion] floating point conversion +# 59| Type = [FloatType] float +# 59| Value = [CStyleCast] 2.0 +# 59| ValueCategory = prvalue +# 59| expr: [Literal] 2.0 +# 59| Type = [DoubleType] double +# 59| Value = [Literal] 2.0 +# 59| ValueCategory = prvalue +# 60| 1: [DeclStmt] declaration +# 60| 0: [VariableDeclarationEntry] definition of d +# 60| Type = [DoubleType] double +# 60| init: [Initializer] initializer for d +# 60| expr: [Literal] 3.0 +# 60| Type = [DoubleType] double +# 60| Value = [Literal] 3.0 +# 60| ValueCategory = prvalue +# 61| 2: [DeclStmt] declaration +# 61| 0: [VariableDeclarationEntry] definition of ld +# 61| Type = [LongDoubleType] long double +# 61| init: [Initializer] initializer for ld +# 61| expr: [CStyleCast] (long double)... +# 61| Conversion = [FloatingPointConversion] floating point conversion +# 61| Type = [LongDoubleType] long double +# 61| Value = [CStyleCast] 5.0 +# 61| ValueCategory = prvalue +# 61| expr: [Literal] 5.0 +# 61| Type = [DoubleType] double +# 61| Value = [Literal] 5.0 +# 61| ValueCategory = prvalue +# 62| 3: [DeclStmt] declaration +# 62| 0: [VariableDeclarationEntry] definition of cf +# 62| Type = [ArithmeticType] _Complex float +# 62| init: [Initializer] initializer for cf +# 62| expr: [CStyleCast] (_Complex float)... +# 62| Conversion = [FloatingPointConversion] floating point conversion +# 62| Type = [ArithmeticType] _Complex float +# 62| ValueCategory = prvalue +# 62| expr: [Literal] 7.0 +# 62| Type = [DoubleType] double +# 62| Value = [Literal] 7.0 +# 62| ValueCategory = prvalue +# 63| 4: [DeclStmt] declaration +# 63| 0: [VariableDeclarationEntry] definition of cd +# 63| Type = [ArithmeticType] _Complex double +# 63| init: [Initializer] initializer for cd +# 63| expr: [CStyleCast] (_Complex double)... +# 63| Conversion = [FloatingPointConversion] floating point conversion +# 63| Type = [ArithmeticType] _Complex double +# 63| ValueCategory = prvalue +# 63| expr: [Literal] 11.0 +# 63| Type = [DoubleType] double +# 63| Value = [Literal] 11.0 +# 63| ValueCategory = prvalue +# 64| 5: [DeclStmt] declaration +# 64| 0: [VariableDeclarationEntry] definition of cld +# 64| Type = [ArithmeticType] _Complex long double +# 64| init: [Initializer] initializer for cld +# 64| expr: [CStyleCast] (_Complex long double)... +# 64| Conversion = [FloatingPointConversion] floating point conversion +# 64| Type = [ArithmeticType] _Complex long double +# 64| ValueCategory = prvalue +# 64| expr: [Literal] 13.0 +# 64| Type = [DoubleType] double +# 64| Value = [Literal] 13.0 +# 64| ValueCategory = prvalue +# 65| 6: [DeclStmt] declaration +# 65| 0: [VariableDeclarationEntry] definition of jf +# 65| Type = [ArithmeticType] _Imaginary float +# 65| init: [Initializer] initializer for jf +# 65| expr: [Literal] 1.0i +# 65| Type = [ArithmeticType] _Imaginary float +# 65| Value = [Literal] 1.0i +# 65| ValueCategory = prvalue +# 66| 7: [DeclStmt] declaration +# 66| 0: [VariableDeclarationEntry] definition of jd +# 66| Type = [ArithmeticType] _Imaginary double +# 66| init: [Initializer] initializer for jd +# 66| expr: [CStyleCast] (_Imaginary double)... +# 66| Conversion = [FloatingPointConversion] floating point conversion +# 66| Type = [ArithmeticType] _Imaginary double +# 66| ValueCategory = prvalue +# 66| expr: [Literal] 1.0i +# 66| Type = [ArithmeticType] _Imaginary float +# 66| Value = [Literal] 1.0i +# 66| ValueCategory = prvalue +# 67| 8: [DeclStmt] declaration +# 67| 0: [VariableDeclarationEntry] definition of jld +# 67| Type = [ArithmeticType] _Imaginary long double +# 67| init: [Initializer] initializer for jld +# 67| expr: [CStyleCast] (_Imaginary long double)... +# 67| Conversion = [FloatingPointConversion] floating point conversion +# 67| Type = [ArithmeticType] _Imaginary long double +# 67| ValueCategory = prvalue +# 67| expr: [Literal] 1.0i +# 67| Type = [ArithmeticType] _Imaginary float +# 67| Value = [Literal] 1.0i +# 67| ValueCategory = prvalue +# 70| 9: [ExprStmt] ExprStmt +# 70| 0: [AssignExpr] ... = ... +# 70| Type = [ArithmeticType] _Complex float +# 70| ValueCategory = prvalue +# 70| 0: [VariableAccess] cf +# 70| Type = [ArithmeticType] _Complex float +# 70| ValueCategory = lvalue +# 70| 1: [VariableAccess] cf +# 70| Type = [ArithmeticType] _Complex float +# 70| ValueCategory = prvalue(load) +# 71| 10: [ExprStmt] ExprStmt +# 71| 0: [AssignExpr] ... = ... +# 71| Type = [ArithmeticType] _Complex float +# 71| ValueCategory = prvalue +# 71| 0: [VariableAccess] cf +# 71| Type = [ArithmeticType] _Complex float +# 71| ValueCategory = lvalue +# 71| 1: [CStyleCast] (_Complex float)... +# 71| Conversion = [FloatingPointConversion] floating point conversion +# 71| Type = [ArithmeticType] _Complex float +# 71| ValueCategory = prvalue +# 71| expr: [VariableAccess] cd +# 71| Type = [ArithmeticType] _Complex double +# 71| ValueCategory = prvalue(load) +# 72| 11: [ExprStmt] ExprStmt +# 72| 0: [AssignExpr] ... = ... +# 72| Type = [ArithmeticType] _Complex float +# 72| ValueCategory = prvalue +# 72| 0: [VariableAccess] cf +# 72| Type = [ArithmeticType] _Complex float +# 72| ValueCategory = lvalue +# 72| 1: [CStyleCast] (_Complex float)... +# 72| Conversion = [FloatingPointConversion] floating point conversion +# 72| Type = [ArithmeticType] _Complex float +# 72| ValueCategory = prvalue +# 72| expr: [VariableAccess] cld +# 72| Type = [ArithmeticType] _Complex long double +# 72| ValueCategory = prvalue(load) +# 73| 12: [ExprStmt] ExprStmt +# 73| 0: [AssignExpr] ... = ... +# 73| Type = [ArithmeticType] _Complex double +# 73| ValueCategory = prvalue +# 73| 0: [VariableAccess] cd +# 73| Type = [ArithmeticType] _Complex double +# 73| ValueCategory = lvalue +# 73| 1: [CStyleCast] (_Complex double)... +# 73| Conversion = [FloatingPointConversion] floating point conversion +# 73| Type = [ArithmeticType] _Complex double +# 73| ValueCategory = prvalue +# 73| expr: [VariableAccess] cf +# 73| Type = [ArithmeticType] _Complex float +# 73| ValueCategory = prvalue(load) +# 74| 13: [ExprStmt] ExprStmt +# 74| 0: [AssignExpr] ... = ... +# 74| Type = [ArithmeticType] _Complex double +# 74| ValueCategory = prvalue +# 74| 0: [VariableAccess] cd +# 74| Type = [ArithmeticType] _Complex double +# 74| ValueCategory = lvalue +# 74| 1: [VariableAccess] cd +# 74| Type = [ArithmeticType] _Complex double +# 74| ValueCategory = prvalue(load) +# 75| 14: [ExprStmt] ExprStmt +# 75| 0: [AssignExpr] ... = ... +# 75| Type = [ArithmeticType] _Complex double +# 75| ValueCategory = prvalue +# 75| 0: [VariableAccess] cd +# 75| Type = [ArithmeticType] _Complex double +# 75| ValueCategory = lvalue +# 75| 1: [CStyleCast] (_Complex double)... +# 75| Conversion = [FloatingPointConversion] floating point conversion +# 75| Type = [ArithmeticType] _Complex double +# 75| ValueCategory = prvalue +# 75| expr: [VariableAccess] cld +# 75| Type = [ArithmeticType] _Complex long double +# 75| ValueCategory = prvalue(load) +# 76| 15: [ExprStmt] ExprStmt +# 76| 0: [AssignExpr] ... = ... +# 76| Type = [ArithmeticType] _Complex long double +# 76| ValueCategory = prvalue +# 76| 0: [VariableAccess] cld +# 76| Type = [ArithmeticType] _Complex long double +# 76| ValueCategory = lvalue +# 76| 1: [CStyleCast] (_Complex long double)... +# 76| Conversion = [FloatingPointConversion] floating point conversion +# 76| Type = [ArithmeticType] _Complex long double +# 76| ValueCategory = prvalue +# 76| expr: [VariableAccess] cf +# 76| Type = [ArithmeticType] _Complex float +# 76| ValueCategory = prvalue(load) +# 77| 16: [ExprStmt] ExprStmt +# 77| 0: [AssignExpr] ... = ... +# 77| Type = [ArithmeticType] _Complex long double +# 77| ValueCategory = prvalue +# 77| 0: [VariableAccess] cld +# 77| Type = [ArithmeticType] _Complex long double +# 77| ValueCategory = lvalue +# 77| 1: [CStyleCast] (_Complex long double)... +# 77| Conversion = [FloatingPointConversion] floating point conversion +# 77| Type = [ArithmeticType] _Complex long double +# 77| ValueCategory = prvalue +# 77| expr: [VariableAccess] cd +# 77| Type = [ArithmeticType] _Complex double +# 77| ValueCategory = prvalue(load) +# 78| 17: [ExprStmt] ExprStmt +# 78| 0: [AssignExpr] ... = ... +# 78| Type = [ArithmeticType] _Complex long double +# 78| ValueCategory = prvalue +# 78| 0: [VariableAccess] cld +# 78| Type = [ArithmeticType] _Complex long double +# 78| ValueCategory = lvalue +# 78| 1: [VariableAccess] cld +# 78| Type = [ArithmeticType] _Complex long double +# 78| ValueCategory = prvalue(load) +# 81| 18: [ExprStmt] ExprStmt +# 81| 0: [AssignExpr] ... = ... +# 81| Type = [ArithmeticType] _Complex float +# 81| ValueCategory = prvalue +# 81| 0: [VariableAccess] cf +# 81| Type = [ArithmeticType] _Complex float +# 81| ValueCategory = lvalue +# 81| 1: [CStyleCast] (_Complex float)... +# 81| Conversion = [FloatingPointConversion] floating point conversion +# 81| Type = [ArithmeticType] _Complex float +# 81| ValueCategory = prvalue +# 81| expr: [VariableAccess] f +# 81| Type = [FloatType] float +# 81| ValueCategory = prvalue(load) +# 82| 19: [ExprStmt] ExprStmt +# 82| 0: [AssignExpr] ... = ... +# 82| Type = [ArithmeticType] _Complex float +# 82| ValueCategory = prvalue +# 82| 0: [VariableAccess] cf +# 82| Type = [ArithmeticType] _Complex float +# 82| ValueCategory = lvalue +# 82| 1: [CStyleCast] (_Complex float)... +# 82| Conversion = [FloatingPointConversion] floating point conversion +# 82| Type = [ArithmeticType] _Complex float +# 82| ValueCategory = prvalue +# 82| expr: [VariableAccess] d +# 82| Type = [DoubleType] double +# 82| ValueCategory = prvalue(load) +# 83| 20: [ExprStmt] ExprStmt +# 83| 0: [AssignExpr] ... = ... +# 83| Type = [ArithmeticType] _Complex float +# 83| ValueCategory = prvalue +# 83| 0: [VariableAccess] cf +# 83| Type = [ArithmeticType] _Complex float +# 83| ValueCategory = lvalue +# 83| 1: [CStyleCast] (_Complex float)... +# 83| Conversion = [FloatingPointConversion] floating point conversion +# 83| Type = [ArithmeticType] _Complex float +# 83| ValueCategory = prvalue +# 83| expr: [VariableAccess] ld +# 83| Type = [LongDoubleType] long double +# 83| ValueCategory = prvalue(load) +# 84| 21: [ExprStmt] ExprStmt +# 84| 0: [AssignExpr] ... = ... +# 84| Type = [ArithmeticType] _Complex double +# 84| ValueCategory = prvalue +# 84| 0: [VariableAccess] cd +# 84| Type = [ArithmeticType] _Complex double +# 84| ValueCategory = lvalue +# 84| 1: [CStyleCast] (_Complex double)... +# 84| Conversion = [FloatingPointConversion] floating point conversion +# 84| Type = [ArithmeticType] _Complex double +# 84| ValueCategory = prvalue +# 84| expr: [VariableAccess] f +# 84| Type = [FloatType] float +# 84| ValueCategory = prvalue(load) +# 85| 22: [ExprStmt] ExprStmt +# 85| 0: [AssignExpr] ... = ... +# 85| Type = [ArithmeticType] _Complex double +# 85| ValueCategory = prvalue +# 85| 0: [VariableAccess] cd +# 85| Type = [ArithmeticType] _Complex double +# 85| ValueCategory = lvalue +# 85| 1: [CStyleCast] (_Complex double)... +# 85| Conversion = [FloatingPointConversion] floating point conversion +# 85| Type = [ArithmeticType] _Complex double +# 85| ValueCategory = prvalue +# 85| expr: [VariableAccess] d +# 85| Type = [DoubleType] double +# 85| ValueCategory = prvalue(load) +# 86| 23: [ExprStmt] ExprStmt +# 86| 0: [AssignExpr] ... = ... +# 86| Type = [ArithmeticType] _Complex double +# 86| ValueCategory = prvalue +# 86| 0: [VariableAccess] cd +# 86| Type = [ArithmeticType] _Complex double +# 86| ValueCategory = lvalue +# 86| 1: [CStyleCast] (_Complex double)... +# 86| Conversion = [FloatingPointConversion] floating point conversion +# 86| Type = [ArithmeticType] _Complex double +# 86| ValueCategory = prvalue +# 86| expr: [VariableAccess] ld +# 86| Type = [LongDoubleType] long double +# 86| ValueCategory = prvalue(load) +# 87| 24: [ExprStmt] ExprStmt +# 87| 0: [AssignExpr] ... = ... +# 87| Type = [ArithmeticType] _Complex long double +# 87| ValueCategory = prvalue +# 87| 0: [VariableAccess] cld +# 87| Type = [ArithmeticType] _Complex long double +# 87| ValueCategory = lvalue +# 87| 1: [CStyleCast] (_Complex long double)... +# 87| Conversion = [FloatingPointConversion] floating point conversion +# 87| Type = [ArithmeticType] _Complex long double +# 87| ValueCategory = prvalue +# 87| expr: [VariableAccess] f +# 87| Type = [FloatType] float +# 87| ValueCategory = prvalue(load) +# 88| 25: [ExprStmt] ExprStmt +# 88| 0: [AssignExpr] ... = ... +# 88| Type = [ArithmeticType] _Complex long double +# 88| ValueCategory = prvalue +# 88| 0: [VariableAccess] cld +# 88| Type = [ArithmeticType] _Complex long double +# 88| ValueCategory = lvalue +# 88| 1: [CStyleCast] (_Complex long double)... +# 88| Conversion = [FloatingPointConversion] floating point conversion +# 88| Type = [ArithmeticType] _Complex long double +# 88| ValueCategory = prvalue +# 88| expr: [VariableAccess] d +# 88| Type = [DoubleType] double +# 88| ValueCategory = prvalue(load) +# 89| 26: [ExprStmt] ExprStmt +# 89| 0: [AssignExpr] ... = ... +# 89| Type = [ArithmeticType] _Complex long double +# 89| ValueCategory = prvalue +# 89| 0: [VariableAccess] cld +# 89| Type = [ArithmeticType] _Complex long double +# 89| ValueCategory = lvalue +# 89| 1: [CStyleCast] (_Complex long double)... +# 89| Conversion = [FloatingPointConversion] floating point conversion +# 89| Type = [ArithmeticType] _Complex long double +# 89| ValueCategory = prvalue +# 89| expr: [VariableAccess] ld +# 89| Type = [LongDoubleType] long double +# 89| ValueCategory = prvalue(load) +# 92| 27: [ExprStmt] ExprStmt +# 92| 0: [AssignExpr] ... = ... +# 92| Type = [FloatType] float +# 92| ValueCategory = prvalue +# 92| 0: [VariableAccess] f +# 92| Type = [FloatType] float +# 92| ValueCategory = lvalue +# 92| 1: [CStyleCast] (float)... +# 92| Conversion = [FloatingPointConversion] floating point conversion +# 92| Type = [FloatType] float +# 92| ValueCategory = prvalue +# 92| expr: [VariableAccess] cf +# 92| Type = [ArithmeticType] _Complex float +# 92| ValueCategory = prvalue(load) +# 93| 28: [ExprStmt] ExprStmt +# 93| 0: [AssignExpr] ... = ... +# 93| Type = [FloatType] float +# 93| ValueCategory = prvalue +# 93| 0: [VariableAccess] f +# 93| Type = [FloatType] float +# 93| ValueCategory = lvalue +# 93| 1: [CStyleCast] (float)... +# 93| Conversion = [FloatingPointConversion] floating point conversion +# 93| Type = [FloatType] float +# 93| ValueCategory = prvalue +# 93| expr: [VariableAccess] cd +# 93| Type = [ArithmeticType] _Complex double +# 93| ValueCategory = prvalue(load) +# 94| 29: [ExprStmt] ExprStmt +# 94| 0: [AssignExpr] ... = ... +# 94| Type = [FloatType] float +# 94| ValueCategory = prvalue +# 94| 0: [VariableAccess] f +# 94| Type = [FloatType] float +# 94| ValueCategory = lvalue +# 94| 1: [CStyleCast] (float)... +# 94| Conversion = [FloatingPointConversion] floating point conversion +# 94| Type = [FloatType] float +# 94| ValueCategory = prvalue +# 94| expr: [VariableAccess] cld +# 94| Type = [ArithmeticType] _Complex long double +# 94| ValueCategory = prvalue(load) +# 95| 30: [ExprStmt] ExprStmt +# 95| 0: [AssignExpr] ... = ... +# 95| Type = [DoubleType] double +# 95| ValueCategory = prvalue +# 95| 0: [VariableAccess] d +# 95| Type = [DoubleType] double +# 95| ValueCategory = lvalue +# 95| 1: [CStyleCast] (double)... +# 95| Conversion = [FloatingPointConversion] floating point conversion +# 95| Type = [DoubleType] double +# 95| ValueCategory = prvalue +# 95| expr: [VariableAccess] cf +# 95| Type = [ArithmeticType] _Complex float +# 95| ValueCategory = prvalue(load) +# 96| 31: [ExprStmt] ExprStmt +# 96| 0: [AssignExpr] ... = ... +# 96| Type = [DoubleType] double +# 96| ValueCategory = prvalue +# 96| 0: [VariableAccess] d +# 96| Type = [DoubleType] double +# 96| ValueCategory = lvalue +# 96| 1: [CStyleCast] (double)... +# 96| Conversion = [FloatingPointConversion] floating point conversion +# 96| Type = [DoubleType] double +# 96| ValueCategory = prvalue +# 96| expr: [VariableAccess] cd +# 96| Type = [ArithmeticType] _Complex double +# 96| ValueCategory = prvalue(load) +# 97| 32: [ExprStmt] ExprStmt +# 97| 0: [AssignExpr] ... = ... +# 97| Type = [DoubleType] double +# 97| ValueCategory = prvalue +# 97| 0: [VariableAccess] d +# 97| Type = [DoubleType] double +# 97| ValueCategory = lvalue +# 97| 1: [CStyleCast] (double)... +# 97| Conversion = [FloatingPointConversion] floating point conversion +# 97| Type = [DoubleType] double +# 97| ValueCategory = prvalue +# 97| expr: [VariableAccess] cld +# 97| Type = [ArithmeticType] _Complex long double +# 97| ValueCategory = prvalue(load) +# 98| 33: [ExprStmt] ExprStmt +# 98| 0: [AssignExpr] ... = ... +# 98| Type = [LongDoubleType] long double +# 98| ValueCategory = prvalue +# 98| 0: [VariableAccess] ld +# 98| Type = [LongDoubleType] long double +# 98| ValueCategory = lvalue +# 98| 1: [CStyleCast] (long double)... +# 98| Conversion = [FloatingPointConversion] floating point conversion +# 98| Type = [LongDoubleType] long double +# 98| ValueCategory = prvalue +# 98| expr: [VariableAccess] cf +# 98| Type = [ArithmeticType] _Complex float +# 98| ValueCategory = prvalue(load) +# 99| 34: [ExprStmt] ExprStmt +# 99| 0: [AssignExpr] ... = ... +# 99| Type = [LongDoubleType] long double +# 99| ValueCategory = prvalue +# 99| 0: [VariableAccess] ld +# 99| Type = [LongDoubleType] long double +# 99| ValueCategory = lvalue +# 99| 1: [CStyleCast] (long double)... +# 99| Conversion = [FloatingPointConversion] floating point conversion +# 99| Type = [LongDoubleType] long double +# 99| ValueCategory = prvalue +# 99| expr: [VariableAccess] cd +# 99| Type = [ArithmeticType] _Complex double +# 99| ValueCategory = prvalue(load) +# 100| 35: [ExprStmt] ExprStmt +# 100| 0: [AssignExpr] ... = ... +# 100| Type = [LongDoubleType] long double +# 100| ValueCategory = prvalue +# 100| 0: [VariableAccess] ld +# 100| Type = [LongDoubleType] long double +# 100| ValueCategory = lvalue +# 100| 1: [CStyleCast] (long double)... +# 100| Conversion = [FloatingPointConversion] floating point conversion +# 100| Type = [LongDoubleType] long double +# 100| ValueCategory = prvalue +# 100| expr: [VariableAccess] cld +# 100| Type = [ArithmeticType] _Complex long double +# 100| ValueCategory = prvalue(load) +# 103| 36: [ExprStmt] ExprStmt +# 103| 0: [AssignExpr] ... = ... +# 103| Type = [ArithmeticType] _Complex float +# 103| ValueCategory = prvalue +# 103| 0: [VariableAccess] cf +# 103| Type = [ArithmeticType] _Complex float +# 103| ValueCategory = lvalue +# 103| 1: [CStyleCast] (_Complex float)... +# 103| Conversion = [FloatingPointConversion] floating point conversion +# 103| Type = [ArithmeticType] _Complex float +# 103| ValueCategory = prvalue +# 103| expr: [VariableAccess] jf +# 103| Type = [ArithmeticType] _Imaginary float +# 103| ValueCategory = prvalue(load) +# 104| 37: [ExprStmt] ExprStmt +# 104| 0: [AssignExpr] ... = ... +# 104| Type = [ArithmeticType] _Complex float +# 104| ValueCategory = prvalue +# 104| 0: [VariableAccess] cf +# 104| Type = [ArithmeticType] _Complex float +# 104| ValueCategory = lvalue +# 104| 1: [CStyleCast] (_Complex float)... +# 104| Conversion = [FloatingPointConversion] floating point conversion +# 104| Type = [ArithmeticType] _Complex float +# 104| ValueCategory = prvalue +# 104| expr: [VariableAccess] jd +# 104| Type = [ArithmeticType] _Imaginary double +# 104| ValueCategory = prvalue(load) +# 105| 38: [ExprStmt] ExprStmt +# 105| 0: [AssignExpr] ... = ... +# 105| Type = [ArithmeticType] _Complex float +# 105| ValueCategory = prvalue +# 105| 0: [VariableAccess] cf +# 105| Type = [ArithmeticType] _Complex float +# 105| ValueCategory = lvalue +# 105| 1: [CStyleCast] (_Complex float)... +# 105| Conversion = [FloatingPointConversion] floating point conversion +# 105| Type = [ArithmeticType] _Complex float +# 105| ValueCategory = prvalue +# 105| expr: [VariableAccess] jld +# 105| Type = [ArithmeticType] _Imaginary long double +# 105| ValueCategory = prvalue(load) +# 106| 39: [ExprStmt] ExprStmt +# 106| 0: [AssignExpr] ... = ... +# 106| Type = [ArithmeticType] _Complex double +# 106| ValueCategory = prvalue +# 106| 0: [VariableAccess] cd +# 106| Type = [ArithmeticType] _Complex double +# 106| ValueCategory = lvalue +# 106| 1: [CStyleCast] (_Complex double)... +# 106| Conversion = [FloatingPointConversion] floating point conversion +# 106| Type = [ArithmeticType] _Complex double +# 106| ValueCategory = prvalue +# 106| expr: [VariableAccess] jf +# 106| Type = [ArithmeticType] _Imaginary float +# 106| ValueCategory = prvalue(load) +# 107| 40: [ExprStmt] ExprStmt +# 107| 0: [AssignExpr] ... = ... +# 107| Type = [ArithmeticType] _Complex double +# 107| ValueCategory = prvalue +# 107| 0: [VariableAccess] cd +# 107| Type = [ArithmeticType] _Complex double +# 107| ValueCategory = lvalue +# 107| 1: [CStyleCast] (_Complex double)... +# 107| Conversion = [FloatingPointConversion] floating point conversion +# 107| Type = [ArithmeticType] _Complex double +# 107| ValueCategory = prvalue +# 107| expr: [VariableAccess] jd +# 107| Type = [ArithmeticType] _Imaginary double +# 107| ValueCategory = prvalue(load) +# 108| 41: [ExprStmt] ExprStmt +# 108| 0: [AssignExpr] ... = ... +# 108| Type = [ArithmeticType] _Complex double +# 108| ValueCategory = prvalue +# 108| 0: [VariableAccess] cd +# 108| Type = [ArithmeticType] _Complex double +# 108| ValueCategory = lvalue +# 108| 1: [CStyleCast] (_Complex double)... +# 108| Conversion = [FloatingPointConversion] floating point conversion +# 108| Type = [ArithmeticType] _Complex double +# 108| ValueCategory = prvalue +# 108| expr: [VariableAccess] jld +# 108| Type = [ArithmeticType] _Imaginary long double +# 108| ValueCategory = prvalue(load) +# 109| 42: [ExprStmt] ExprStmt +# 109| 0: [AssignExpr] ... = ... +# 109| Type = [ArithmeticType] _Complex long double +# 109| ValueCategory = prvalue +# 109| 0: [VariableAccess] cld +# 109| Type = [ArithmeticType] _Complex long double +# 109| ValueCategory = lvalue +# 109| 1: [CStyleCast] (_Complex long double)... +# 109| Conversion = [FloatingPointConversion] floating point conversion +# 109| Type = [ArithmeticType] _Complex long double +# 109| ValueCategory = prvalue +# 109| expr: [VariableAccess] jf +# 109| Type = [ArithmeticType] _Imaginary float +# 109| ValueCategory = prvalue(load) +# 110| 43: [ExprStmt] ExprStmt +# 110| 0: [AssignExpr] ... = ... +# 110| Type = [ArithmeticType] _Complex long double +# 110| ValueCategory = prvalue +# 110| 0: [VariableAccess] cld +# 110| Type = [ArithmeticType] _Complex long double +# 110| ValueCategory = lvalue +# 110| 1: [CStyleCast] (_Complex long double)... +# 110| Conversion = [FloatingPointConversion] floating point conversion +# 110| Type = [ArithmeticType] _Complex long double +# 110| ValueCategory = prvalue +# 110| expr: [VariableAccess] jd +# 110| Type = [ArithmeticType] _Imaginary double +# 110| ValueCategory = prvalue(load) +# 111| 44: [ExprStmt] ExprStmt +# 111| 0: [AssignExpr] ... = ... +# 111| Type = [ArithmeticType] _Complex long double +# 111| ValueCategory = prvalue +# 111| 0: [VariableAccess] cld +# 111| Type = [ArithmeticType] _Complex long double +# 111| ValueCategory = lvalue +# 111| 1: [CStyleCast] (_Complex long double)... +# 111| Conversion = [FloatingPointConversion] floating point conversion +# 111| Type = [ArithmeticType] _Complex long double +# 111| ValueCategory = prvalue +# 111| expr: [VariableAccess] jld +# 111| Type = [ArithmeticType] _Imaginary long double +# 111| ValueCategory = prvalue(load) +# 114| 45: [ExprStmt] ExprStmt +# 114| 0: [AssignExpr] ... = ... +# 114| Type = [ArithmeticType] _Imaginary float +# 114| ValueCategory = prvalue +# 114| 0: [VariableAccess] jf +# 114| Type = [ArithmeticType] _Imaginary float +# 114| ValueCategory = lvalue +# 114| 1: [CStyleCast] (_Imaginary float)... +# 114| Conversion = [FloatingPointConversion] floating point conversion +# 114| Type = [ArithmeticType] _Imaginary float +# 114| ValueCategory = prvalue +# 114| expr: [VariableAccess] cf +# 114| Type = [ArithmeticType] _Complex float +# 114| ValueCategory = prvalue(load) +# 115| 46: [ExprStmt] ExprStmt +# 115| 0: [AssignExpr] ... = ... +# 115| Type = [ArithmeticType] _Imaginary float +# 115| ValueCategory = prvalue +# 115| 0: [VariableAccess] jf +# 115| Type = [ArithmeticType] _Imaginary float +# 115| ValueCategory = lvalue +# 115| 1: [CStyleCast] (_Imaginary float)... +# 115| Conversion = [FloatingPointConversion] floating point conversion +# 115| Type = [ArithmeticType] _Imaginary float +# 115| ValueCategory = prvalue +# 115| expr: [VariableAccess] cd +# 115| Type = [ArithmeticType] _Complex double +# 115| ValueCategory = prvalue(load) +# 116| 47: [ExprStmt] ExprStmt +# 116| 0: [AssignExpr] ... = ... +# 116| Type = [ArithmeticType] _Imaginary float +# 116| ValueCategory = prvalue +# 116| 0: [VariableAccess] jf +# 116| Type = [ArithmeticType] _Imaginary float +# 116| ValueCategory = lvalue +# 116| 1: [CStyleCast] (_Imaginary float)... +# 116| Conversion = [FloatingPointConversion] floating point conversion +# 116| Type = [ArithmeticType] _Imaginary float +# 116| ValueCategory = prvalue +# 116| expr: [VariableAccess] cld +# 116| Type = [ArithmeticType] _Complex long double +# 116| ValueCategory = prvalue(load) +# 117| 48: [ExprStmt] ExprStmt +# 117| 0: [AssignExpr] ... = ... +# 117| Type = [ArithmeticType] _Imaginary double +# 117| ValueCategory = prvalue +# 117| 0: [VariableAccess] jd +# 117| Type = [ArithmeticType] _Imaginary double +# 117| ValueCategory = lvalue +# 117| 1: [CStyleCast] (_Imaginary double)... +# 117| Conversion = [FloatingPointConversion] floating point conversion +# 117| Type = [ArithmeticType] _Imaginary double +# 117| ValueCategory = prvalue +# 117| expr: [VariableAccess] cf +# 117| Type = [ArithmeticType] _Complex float +# 117| ValueCategory = prvalue(load) +# 118| 49: [ExprStmt] ExprStmt +# 118| 0: [AssignExpr] ... = ... +# 118| Type = [ArithmeticType] _Imaginary double +# 118| ValueCategory = prvalue +# 118| 0: [VariableAccess] jd +# 118| Type = [ArithmeticType] _Imaginary double +# 118| ValueCategory = lvalue +# 118| 1: [CStyleCast] (_Imaginary double)... +# 118| Conversion = [FloatingPointConversion] floating point conversion +# 118| Type = [ArithmeticType] _Imaginary double +# 118| ValueCategory = prvalue +# 118| expr: [VariableAccess] cd +# 118| Type = [ArithmeticType] _Complex double +# 118| ValueCategory = prvalue(load) +# 119| 50: [ExprStmt] ExprStmt +# 119| 0: [AssignExpr] ... = ... +# 119| Type = [ArithmeticType] _Imaginary double +# 119| ValueCategory = prvalue +# 119| 0: [VariableAccess] jd +# 119| Type = [ArithmeticType] _Imaginary double +# 119| ValueCategory = lvalue +# 119| 1: [CStyleCast] (_Imaginary double)... +# 119| Conversion = [FloatingPointConversion] floating point conversion +# 119| Type = [ArithmeticType] _Imaginary double +# 119| ValueCategory = prvalue +# 119| expr: [VariableAccess] cld +# 119| Type = [ArithmeticType] _Complex long double +# 119| ValueCategory = prvalue(load) +# 120| 51: [ExprStmt] ExprStmt +# 120| 0: [AssignExpr] ... = ... +# 120| Type = [ArithmeticType] _Imaginary long double +# 120| ValueCategory = prvalue +# 120| 0: [VariableAccess] jld +# 120| Type = [ArithmeticType] _Imaginary long double +# 120| ValueCategory = lvalue +# 120| 1: [CStyleCast] (_Imaginary long double)... +# 120| Conversion = [FloatingPointConversion] floating point conversion +# 120| Type = [ArithmeticType] _Imaginary long double +# 120| ValueCategory = prvalue +# 120| expr: [VariableAccess] cf +# 120| Type = [ArithmeticType] _Complex float +# 120| ValueCategory = prvalue(load) +# 121| 52: [ExprStmt] ExprStmt +# 121| 0: [AssignExpr] ... = ... +# 121| Type = [ArithmeticType] _Imaginary long double +# 121| ValueCategory = prvalue +# 121| 0: [VariableAccess] jld +# 121| Type = [ArithmeticType] _Imaginary long double +# 121| ValueCategory = lvalue +# 121| 1: [CStyleCast] (_Imaginary long double)... +# 121| Conversion = [FloatingPointConversion] floating point conversion +# 121| Type = [ArithmeticType] _Imaginary long double +# 121| ValueCategory = prvalue +# 121| expr: [VariableAccess] cd +# 121| Type = [ArithmeticType] _Complex double +# 121| ValueCategory = prvalue(load) +# 122| 53: [ExprStmt] ExprStmt +# 122| 0: [AssignExpr] ... = ... +# 122| Type = [ArithmeticType] _Imaginary long double +# 122| ValueCategory = prvalue +# 122| 0: [VariableAccess] jld +# 122| Type = [ArithmeticType] _Imaginary long double +# 122| ValueCategory = lvalue +# 122| 1: [CStyleCast] (_Imaginary long double)... +# 122| Conversion = [FloatingPointConversion] floating point conversion +# 122| Type = [ArithmeticType] _Imaginary long double +# 122| ValueCategory = prvalue +# 122| expr: [VariableAccess] cld +# 122| Type = [ArithmeticType] _Complex long double +# 122| ValueCategory = prvalue(load) +# 125| 54: [ExprStmt] ExprStmt +# 125| 0: [AssignExpr] ... = ... +# 125| Type = [ArithmeticType] _Imaginary float +# 125| ValueCategory = prvalue +# 125| 0: [VariableAccess] jf +# 125| Type = [ArithmeticType] _Imaginary float +# 125| ValueCategory = lvalue +# 125| 1: [CStyleCast] (_Imaginary float)... +# 125| Conversion = [FloatingPointConversion] floating point conversion +# 125| Type = [ArithmeticType] _Imaginary float +# 125| ValueCategory = prvalue +# 125| expr: [VariableAccess] f +# 125| Type = [FloatType] float +# 125| ValueCategory = prvalue(load) +# 126| 55: [ExprStmt] ExprStmt +# 126| 0: [AssignExpr] ... = ... +# 126| Type = [ArithmeticType] _Imaginary float +# 126| ValueCategory = prvalue +# 126| 0: [VariableAccess] jf +# 126| Type = [ArithmeticType] _Imaginary float +# 126| ValueCategory = lvalue +# 126| 1: [CStyleCast] (_Imaginary float)... +# 126| Conversion = [FloatingPointConversion] floating point conversion +# 126| Type = [ArithmeticType] _Imaginary float +# 126| ValueCategory = prvalue +# 126| expr: [VariableAccess] d +# 126| Type = [DoubleType] double +# 126| ValueCategory = prvalue(load) +# 127| 56: [ExprStmt] ExprStmt +# 127| 0: [AssignExpr] ... = ... +# 127| Type = [ArithmeticType] _Imaginary float +# 127| ValueCategory = prvalue +# 127| 0: [VariableAccess] jf +# 127| Type = [ArithmeticType] _Imaginary float +# 127| ValueCategory = lvalue +# 127| 1: [CStyleCast] (_Imaginary float)... +# 127| Conversion = [FloatingPointConversion] floating point conversion +# 127| Type = [ArithmeticType] _Imaginary float +# 127| ValueCategory = prvalue +# 127| expr: [VariableAccess] ld +# 127| Type = [LongDoubleType] long double +# 127| ValueCategory = prvalue(load) +# 128| 57: [ExprStmt] ExprStmt +# 128| 0: [AssignExpr] ... = ... +# 128| Type = [ArithmeticType] _Imaginary double +# 128| ValueCategory = prvalue +# 128| 0: [VariableAccess] jd +# 128| Type = [ArithmeticType] _Imaginary double +# 128| ValueCategory = lvalue +# 128| 1: [CStyleCast] (_Imaginary double)... +# 128| Conversion = [FloatingPointConversion] floating point conversion +# 128| Type = [ArithmeticType] _Imaginary double +# 128| ValueCategory = prvalue +# 128| expr: [VariableAccess] f +# 128| Type = [FloatType] float +# 128| ValueCategory = prvalue(load) +# 129| 58: [ExprStmt] ExprStmt +# 129| 0: [AssignExpr] ... = ... +# 129| Type = [ArithmeticType] _Imaginary double +# 129| ValueCategory = prvalue +# 129| 0: [VariableAccess] jd +# 129| Type = [ArithmeticType] _Imaginary double +# 129| ValueCategory = lvalue +# 129| 1: [CStyleCast] (_Imaginary double)... +# 129| Conversion = [FloatingPointConversion] floating point conversion +# 129| Type = [ArithmeticType] _Imaginary double +# 129| ValueCategory = prvalue +# 129| expr: [VariableAccess] d +# 129| Type = [DoubleType] double +# 129| ValueCategory = prvalue(load) +# 130| 59: [ExprStmt] ExprStmt +# 130| 0: [AssignExpr] ... = ... +# 130| Type = [ArithmeticType] _Imaginary double +# 130| ValueCategory = prvalue +# 130| 0: [VariableAccess] jd +# 130| Type = [ArithmeticType] _Imaginary double +# 130| ValueCategory = lvalue +# 130| 1: [CStyleCast] (_Imaginary double)... +# 130| Conversion = [FloatingPointConversion] floating point conversion +# 130| Type = [ArithmeticType] _Imaginary double +# 130| ValueCategory = prvalue +# 130| expr: [VariableAccess] ld +# 130| Type = [LongDoubleType] long double +# 130| ValueCategory = prvalue(load) +# 131| 60: [ExprStmt] ExprStmt +# 131| 0: [AssignExpr] ... = ... +# 131| Type = [ArithmeticType] _Imaginary long double +# 131| ValueCategory = prvalue +# 131| 0: [VariableAccess] jld +# 131| Type = [ArithmeticType] _Imaginary long double +# 131| ValueCategory = lvalue +# 131| 1: [CStyleCast] (_Imaginary long double)... +# 131| Conversion = [FloatingPointConversion] floating point conversion +# 131| Type = [ArithmeticType] _Imaginary long double +# 131| ValueCategory = prvalue +# 131| expr: [VariableAccess] f +# 131| Type = [FloatType] float +# 131| ValueCategory = prvalue(load) +# 132| 61: [ExprStmt] ExprStmt +# 132| 0: [AssignExpr] ... = ... +# 132| Type = [ArithmeticType] _Imaginary long double +# 132| ValueCategory = prvalue +# 132| 0: [VariableAccess] jld +# 132| Type = [ArithmeticType] _Imaginary long double +# 132| ValueCategory = lvalue +# 132| 1: [CStyleCast] (_Imaginary long double)... +# 132| Conversion = [FloatingPointConversion] floating point conversion +# 132| Type = [ArithmeticType] _Imaginary long double +# 132| ValueCategory = prvalue +# 132| expr: [VariableAccess] d +# 132| Type = [DoubleType] double +# 132| ValueCategory = prvalue(load) +# 133| 62: [ExprStmt] ExprStmt +# 133| 0: [AssignExpr] ... = ... +# 133| Type = [ArithmeticType] _Imaginary long double +# 133| ValueCategory = prvalue +# 133| 0: [VariableAccess] jld +# 133| Type = [ArithmeticType] _Imaginary long double +# 133| ValueCategory = lvalue +# 133| 1: [CStyleCast] (_Imaginary long double)... +# 133| Conversion = [FloatingPointConversion] floating point conversion +# 133| Type = [ArithmeticType] _Imaginary long double +# 133| ValueCategory = prvalue +# 133| expr: [VariableAccess] ld +# 133| Type = [LongDoubleType] long double +# 133| ValueCategory = prvalue(load) +# 136| 63: [ExprStmt] ExprStmt +# 136| 0: [AssignExpr] ... = ... +# 136| Type = [FloatType] float +# 136| ValueCategory = prvalue +# 136| 0: [VariableAccess] f +# 136| Type = [FloatType] float +# 136| ValueCategory = lvalue +# 136| 1: [CStyleCast] (float)... +# 136| Conversion = [FloatingPointConversion] floating point conversion +# 136| Type = [FloatType] float +# 136| ValueCategory = prvalue +# 136| expr: [VariableAccess] jf +# 136| Type = [ArithmeticType] _Imaginary float +# 136| ValueCategory = prvalue(load) +# 137| 64: [ExprStmt] ExprStmt +# 137| 0: [AssignExpr] ... = ... +# 137| Type = [FloatType] float +# 137| ValueCategory = prvalue +# 137| 0: [VariableAccess] f +# 137| Type = [FloatType] float +# 137| ValueCategory = lvalue +# 137| 1: [CStyleCast] (float)... +# 137| Conversion = [FloatingPointConversion] floating point conversion +# 137| Type = [FloatType] float +# 137| ValueCategory = prvalue +# 137| expr: [VariableAccess] jd +# 137| Type = [ArithmeticType] _Imaginary double +# 137| ValueCategory = prvalue(load) +# 138| 65: [ExprStmt] ExprStmt +# 138| 0: [AssignExpr] ... = ... +# 138| Type = [FloatType] float +# 138| ValueCategory = prvalue +# 138| 0: [VariableAccess] f +# 138| Type = [FloatType] float +# 138| ValueCategory = lvalue +# 138| 1: [CStyleCast] (float)... +# 138| Conversion = [FloatingPointConversion] floating point conversion +# 138| Type = [FloatType] float +# 138| ValueCategory = prvalue +# 138| expr: [VariableAccess] jld +# 138| Type = [ArithmeticType] _Imaginary long double +# 138| ValueCategory = prvalue(load) +# 139| 66: [ExprStmt] ExprStmt +# 139| 0: [AssignExpr] ... = ... +# 139| Type = [DoubleType] double +# 139| ValueCategory = prvalue +# 139| 0: [VariableAccess] d +# 139| Type = [DoubleType] double +# 139| ValueCategory = lvalue +# 139| 1: [CStyleCast] (double)... +# 139| Conversion = [FloatingPointConversion] floating point conversion +# 139| Type = [DoubleType] double +# 139| ValueCategory = prvalue +# 139| expr: [VariableAccess] jf +# 139| Type = [ArithmeticType] _Imaginary float +# 139| ValueCategory = prvalue(load) +# 140| 67: [ExprStmt] ExprStmt +# 140| 0: [AssignExpr] ... = ... +# 140| Type = [DoubleType] double +# 140| ValueCategory = prvalue +# 140| 0: [VariableAccess] d +# 140| Type = [DoubleType] double +# 140| ValueCategory = lvalue +# 140| 1: [CStyleCast] (double)... +# 140| Conversion = [FloatingPointConversion] floating point conversion +# 140| Type = [DoubleType] double +# 140| ValueCategory = prvalue +# 140| expr: [VariableAccess] jd +# 140| Type = [ArithmeticType] _Imaginary double +# 140| ValueCategory = prvalue(load) +# 141| 68: [ExprStmt] ExprStmt +# 141| 0: [AssignExpr] ... = ... +# 141| Type = [DoubleType] double +# 141| ValueCategory = prvalue +# 141| 0: [VariableAccess] d +# 141| Type = [DoubleType] double +# 141| ValueCategory = lvalue +# 141| 1: [CStyleCast] (double)... +# 141| Conversion = [FloatingPointConversion] floating point conversion +# 141| Type = [DoubleType] double +# 141| ValueCategory = prvalue +# 141| expr: [VariableAccess] jld +# 141| Type = [ArithmeticType] _Imaginary long double +# 141| ValueCategory = prvalue(load) +# 142| 69: [ExprStmt] ExprStmt +# 142| 0: [AssignExpr] ... = ... +# 142| Type = [LongDoubleType] long double +# 142| ValueCategory = prvalue +# 142| 0: [VariableAccess] ld +# 142| Type = [LongDoubleType] long double +# 142| ValueCategory = lvalue +# 142| 1: [CStyleCast] (long double)... +# 142| Conversion = [FloatingPointConversion] floating point conversion +# 142| Type = [LongDoubleType] long double +# 142| ValueCategory = prvalue +# 142| expr: [VariableAccess] jf +# 142| Type = [ArithmeticType] _Imaginary float +# 142| ValueCategory = prvalue(load) +# 143| 70: [ExprStmt] ExprStmt +# 143| 0: [AssignExpr] ... = ... +# 143| Type = [LongDoubleType] long double +# 143| ValueCategory = prvalue +# 143| 0: [VariableAccess] ld +# 143| Type = [LongDoubleType] long double +# 143| ValueCategory = lvalue +# 143| 1: [CStyleCast] (long double)... +# 143| Conversion = [FloatingPointConversion] floating point conversion +# 143| Type = [LongDoubleType] long double +# 143| ValueCategory = prvalue +# 143| expr: [VariableAccess] jd +# 143| Type = [ArithmeticType] _Imaginary double +# 143| ValueCategory = prvalue(load) +# 144| 71: [ExprStmt] ExprStmt +# 144| 0: [AssignExpr] ... = ... +# 144| Type = [LongDoubleType] long double +# 144| ValueCategory = prvalue +# 144| 0: [VariableAccess] ld +# 144| Type = [LongDoubleType] long double +# 144| ValueCategory = lvalue +# 144| 1: [CStyleCast] (long double)... +# 144| Conversion = [FloatingPointConversion] floating point conversion +# 144| Type = [LongDoubleType] long double +# 144| ValueCategory = prvalue +# 144| expr: [VariableAccess] jld +# 144| Type = [ArithmeticType] _Imaginary long double +# 144| ValueCategory = prvalue(load) +# 145| 72: [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 index 51775832586..d2009778ae5 100644 --- a/cpp/ql/test/library-tests/ir/ir/complex.c +++ b/cpp/ql/test/library-tests/ir/ir/complex.c @@ -1,5 +1,147 @@ -void complex_math(void) { - _Complex float cf = 2.0 + 1.0if; - _Complex float cf2 = cf * cf; - double d = cf2; +void complex_literals(void) { + _Complex float cf = 2.0; + cf = __I__; + _Complex double cd = 3.0; + cd = __I__; + _Complex long double cld = 5.0; + cld = __I__; + + _Imaginary float jf = __I__; + _Imaginary double jd = __I__; + _Imaginary long double jld = __I__; } + +void complex_arithmetic(void) { + float f1 = 5.0; + float f2 = 7.0; + float f3; + _Complex float cf1 = 2.0; + _Complex float cf2 = __I__; + _Complex float cf3; + _Imaginary float jf1 = __I__; + _Imaginary float jf2 = __I__; + _Imaginary float jf3; + + // unaryop _Complex + cf3 = +cf1; + cf3 = -cf1; + + // _Complex binaryop _Complex + cf3 = cf1 + cf2; + cf3 = cf1 - cf2; + cf3 = cf1 * cf2; + cf3 = cf1 / cf2; + + // unaryop _Imaginary + jf3 = +jf1; + jf3 = -jf1; + + // _Imaginary binaryop _Imaginary + jf3 = jf1 + jf2; + jf3 = jf1 - jf2; + f3 = jf1 * jf2; // Result is _Real + f3 = jf1 / jf2; // Result is _Real + + // _Imaginary binaryop _Real + cf3 = jf1 + f2; + cf3 = jf1 - f2; + jf3 = jf1 * f2; // Result is _Imaginary + jf3 = jf1 / f2; // Result is _Imaginary + + // _Real binaryop _Imaginary + cf3 = f1 + jf2; + cf3 = f1 - jf2; + jf3 = f1 * jf2; // Result is _Imaginary + jf3 = f1 / jf2; // Result is _Imaginary +} + +void complex_conversions(void) { + float f = 2.0; + double d = 3.0; + long double ld = 5.0; + _Complex float cf = 7.0; + _Complex double cd = 11.0; + _Complex long double cld = 13.0; + _Imaginary float jf = __I__; + _Imaginary double jd = __I__; + _Imaginary long double jld = __I__; + + // _Complex to _Complex + cf = cf; + cf = cd; + cf = cld; + cd = cf; + cd = cd; + cd = cld; + cld = cf; + cld = cd; + cld = cld; + + // _Real to _Complex + cf = f; + cf = d; + cf = ld; + cd = f; + cd = d; + cd = ld; + cld = f; + cld = d; + cld = ld; + + // _Complex to _Real + f = cf; + f = cd; + f = cld; + d = cf; + d = cd; + d = cld; + ld = cf; + ld = cd; + ld = cld; + + // _Imaginary to _Complex + cf = jf; + cf = jd; + cf = jld; + cd = jf; + cd = jd; + cd = jld; + cld = jf; + cld = jd; + cld = jld; + + // _Complex to _Imaginary + jf = cf; + jf = cd; + jf = cld; + jd = cf; + jd = cd; + jd = cld; + jld = cf; + jld = cd; + jld = cld; + + // _Real to _Imaginary + jf = f; + jf = d; + jf = ld; + jd = f; + jd = d; + jd = ld; + jld = f; + jld = d; + jld = ld; + + // _Imaginary to _Real + f = jf; + f = jd; + f = jld; + d = jf; + d = jd; + d = jld; + ld = jf; + ld = jd; + ld = jld; +} + +// semmle-extractor-options: --microsoft --edg --c99 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 66c6711e645..b5f57acaa4c 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -125,37 +125,578 @@ clang.cpp: # 5| v5_9(void) = ExitFunction : complex.c: -# 1| void complex_math() +# 1| void complex_literals() # 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 : +# 1| v1_1(void) = EnterFunction : +# 1| mu1_2(unknown) = AliasedDefinition : +# 1| mu1_3(unknown) = InitializeNonLocal : +# 1| mu1_4(unknown) = UnmodeledDefinition : +# 2| r2_1(glval<_Complex float>) = VariableAddress[cf] : +# 2| r2_2(double) = Constant[2.0] : +# 2| r2_3(_Complex float) = Convert : r2_2 +# 2| mu2_4(_Complex float) = Store : &:r2_1, r2_3 +# 3| r3_1(_Imaginary float) = Constant[1.0i] : +# 3| r3_2(_Complex float) = Convert : r3_1 +# 3| r3_3(glval<_Complex float>) = VariableAddress[cf] : +# 3| mu3_4(_Complex float) = Store : &:r3_3, r3_2 +# 4| r4_1(glval<_Complex double>) = VariableAddress[cd] : +# 4| r4_2(double) = Constant[3.0] : +# 4| r4_3(_Complex double) = Convert : r4_2 +# 4| mu4_4(_Complex double) = Store : &:r4_1, r4_3 +# 5| r5_1(_Imaginary float) = Constant[1.0i] : +# 5| r5_2(_Complex double) = Convert : r5_1 +# 5| r5_3(glval<_Complex double>) = VariableAddress[cd] : +# 5| mu5_4(_Complex double) = Store : &:r5_3, r5_2 +# 6| r6_1(glval<_Complex long double>) = VariableAddress[cld] : +# 6| r6_2(double) = Constant[5.0] : +# 6| r6_3(_Complex long double) = Convert : r6_2 +# 6| mu6_4(_Complex long double) = Store : &:r6_1, r6_3 +# 7| r7_1(_Imaginary float) = Constant[1.0i] : +# 7| r7_2(_Complex long double) = Convert : r7_1 +# 7| r7_3(glval<_Complex long double>) = VariableAddress[cld] : +# 7| mu7_4(_Complex long double) = Store : &:r7_3, r7_2 +# 9| r9_1(glval<_Imaginary float>) = VariableAddress[jf] : +# 9| r9_2(_Imaginary float) = Constant[1.0i] : +# 9| mu9_3(_Imaginary float) = Store : &:r9_1, r9_2 +# 10| r10_1(glval<_Imaginary double>) = VariableAddress[jd] : +# 10| r10_2(_Imaginary float) = Constant[1.0i] : +# 10| r10_3(_Imaginary double) = Convert : r10_2 +# 10| mu10_4(_Imaginary double) = Store : &:r10_1, r10_3 +# 11| r11_1(glval<_Imaginary long double>) = VariableAddress[jld] : +# 11| r11_2(_Imaginary float) = Constant[1.0i] : +# 11| r11_3(_Imaginary long double) = Convert : r11_2 +# 11| mu11_4(_Imaginary long double) = Store : &:r11_1, r11_3 +# 12| v12_1(void) = NoOp : +# 1| v1_5(void) = ReturnVoid : +# 1| v1_6(void) = UnmodeledUse : mu* +# 1| v1_7(void) = AliasedUse : ~mu1_4 +# 1| v1_8(void) = ExitFunction : + +# 14| void complex_arithmetic() +# 14| Block 0 +# 14| v14_1(void) = EnterFunction : +# 14| mu14_2(unknown) = AliasedDefinition : +# 14| mu14_3(unknown) = InitializeNonLocal : +# 14| mu14_4(unknown) = UnmodeledDefinition : +# 15| r15_1(glval) = VariableAddress[f1] : +# 15| r15_2(float) = Constant[5.0] : +# 15| mu15_3(float) = Store : &:r15_1, r15_2 +# 16| r16_1(glval) = VariableAddress[f2] : +# 16| r16_2(float) = Constant[7.0] : +# 16| mu16_3(float) = Store : &:r16_1, r16_2 +# 17| r17_1(glval) = VariableAddress[f3] : +# 17| mu17_2(float) = Uninitialized[f3] : &:r17_1 +# 18| r18_1(glval<_Complex float>) = VariableAddress[cf1] : +# 18| r18_2(double) = Constant[2.0] : +# 18| r18_3(_Complex float) = Convert : r18_2 +# 18| mu18_4(_Complex float) = Store : &:r18_1, r18_3 +# 19| r19_1(glval<_Complex float>) = VariableAddress[cf2] : +# 19| r19_2(_Imaginary float) = Constant[1.0i] : +# 19| r19_3(_Complex float) = Convert : r19_2 +# 19| mu19_4(_Complex float) = Store : &:r19_1, r19_3 +# 20| r20_1(glval<_Complex float>) = VariableAddress[cf3] : +# 20| mu20_2(_Complex float) = Uninitialized[cf3] : &:r20_1 +# 21| r21_1(glval<_Imaginary float>) = VariableAddress[jf1] : +# 21| r21_2(_Imaginary float) = Constant[1.0i] : +# 21| mu21_3(_Imaginary float) = Store : &:r21_1, r21_2 +# 22| r22_1(glval<_Imaginary float>) = VariableAddress[jf2] : +# 22| r22_2(_Imaginary float) = Constant[1.0i] : +# 22| mu22_3(_Imaginary float) = Store : &:r22_1, r22_2 +# 23| r23_1(glval<_Imaginary float>) = VariableAddress[jf3] : +# 23| mu23_2(_Imaginary float) = Uninitialized[jf3] : &:r23_1 +# 26| r26_1(glval<_Complex float>) = VariableAddress[cf1] : +# 26| r26_2(_Complex float) = Load : &:r26_1, ~mu14_4 +# 26| r26_3(_Complex float) = CopyValue : r26_2 +# 26| r26_4(glval<_Complex float>) = VariableAddress[cf3] : +# 26| mu26_5(_Complex float) = Store : &:r26_4, r26_3 +# 27| r27_1(glval<_Complex float>) = VariableAddress[cf1] : +# 27| r27_2(_Complex float) = Load : &:r27_1, ~mu14_4 +# 27| r27_3(_Complex float) = Negate : r27_2 +# 27| r27_4(glval<_Complex float>) = VariableAddress[cf3] : +# 27| mu27_5(_Complex float) = Store : &:r27_4, r27_3 +# 30| r30_1(glval<_Complex float>) = VariableAddress[cf1] : +# 30| r30_2(_Complex float) = Load : &:r30_1, ~mu14_4 +# 30| r30_3(glval<_Complex float>) = VariableAddress[cf2] : +# 30| r30_4(_Complex float) = Load : &:r30_3, ~mu14_4 +# 30| r30_5(_Complex float) = Add : r30_2, r30_4 +# 30| r30_6(glval<_Complex float>) = VariableAddress[cf3] : +# 30| mu30_7(_Complex float) = Store : &:r30_6, r30_5 +# 31| r31_1(glval<_Complex float>) = VariableAddress[cf1] : +# 31| r31_2(_Complex float) = Load : &:r31_1, ~mu14_4 +# 31| r31_3(glval<_Complex float>) = VariableAddress[cf2] : +# 31| r31_4(_Complex float) = Load : &:r31_3, ~mu14_4 +# 31| r31_5(_Complex float) = Sub : r31_2, r31_4 +# 31| r31_6(glval<_Complex float>) = VariableAddress[cf3] : +# 31| mu31_7(_Complex float) = Store : &:r31_6, r31_5 +# 32| r32_1(glval<_Complex float>) = VariableAddress[cf1] : +# 32| r32_2(_Complex float) = Load : &:r32_1, ~mu14_4 +# 32| r32_3(glval<_Complex float>) = VariableAddress[cf2] : +# 32| r32_4(_Complex float) = Load : &:r32_3, ~mu14_4 +# 32| r32_5(_Complex float) = Mul : r32_2, r32_4 +# 32| r32_6(glval<_Complex float>) = VariableAddress[cf3] : +# 32| mu32_7(_Complex float) = Store : &:r32_6, r32_5 +# 33| r33_1(glval<_Complex float>) = VariableAddress[cf1] : +# 33| r33_2(_Complex float) = Load : &:r33_1, ~mu14_4 +# 33| r33_3(glval<_Complex float>) = VariableAddress[cf2] : +# 33| r33_4(_Complex float) = Load : &:r33_3, ~mu14_4 +# 33| r33_5(_Complex float) = Div : r33_2, r33_4 +# 33| r33_6(glval<_Complex float>) = VariableAddress[cf3] : +# 33| mu33_7(_Complex float) = Store : &:r33_6, r33_5 +# 36| r36_1(glval<_Imaginary float>) = VariableAddress[jf1] : +# 36| r36_2(_Imaginary float) = Load : &:r36_1, ~mu14_4 +# 36| r36_3(_Imaginary float) = CopyValue : r36_2 +# 36| r36_4(glval<_Imaginary float>) = VariableAddress[jf3] : +# 36| mu36_5(_Imaginary float) = Store : &:r36_4, r36_3 +# 37| r37_1(glval<_Imaginary float>) = VariableAddress[jf1] : +# 37| r37_2(_Imaginary float) = Load : &:r37_1, ~mu14_4 +# 37| r37_3(_Imaginary float) = Negate : r37_2 +# 37| r37_4(glval<_Imaginary float>) = VariableAddress[jf3] : +# 37| mu37_5(_Imaginary float) = Store : &:r37_4, r37_3 +# 40| r40_1(glval<_Imaginary float>) = VariableAddress[jf1] : +# 40| r40_2(_Imaginary float) = Load : &:r40_1, ~mu14_4 +# 40| r40_3(glval<_Imaginary float>) = VariableAddress[jf2] : +# 40| r40_4(_Imaginary float) = Load : &:r40_3, ~mu14_4 +# 40| r40_5(_Imaginary float) = Add : r40_2, r40_4 +# 40| r40_6(glval<_Imaginary float>) = VariableAddress[jf3] : +# 40| mu40_7(_Imaginary float) = Store : &:r40_6, r40_5 +# 41| r41_1(glval<_Imaginary float>) = VariableAddress[jf1] : +# 41| r41_2(_Imaginary float) = Load : &:r41_1, ~mu14_4 +# 41| r41_3(glval<_Imaginary float>) = VariableAddress[jf2] : +# 41| r41_4(_Imaginary float) = Load : &:r41_3, ~mu14_4 +# 41| r41_5(_Imaginary float) = Sub : r41_2, r41_4 +# 41| r41_6(glval<_Imaginary float>) = VariableAddress[jf3] : +# 41| mu41_7(_Imaginary float) = Store : &:r41_6, r41_5 +# 42| r42_1(glval<_Imaginary float>) = VariableAddress[jf1] : +# 42| r42_2(_Imaginary float) = Load : &:r42_1, ~mu14_4 +# 42| r42_3(glval<_Imaginary float>) = VariableAddress[jf2] : +# 42| r42_4(_Imaginary float) = Load : &:r42_3, ~mu14_4 +# 42| r42_5(float) = Mul : r42_2, r42_4 +# 42| r42_6(glval) = VariableAddress[f3] : +# 42| mu42_7(float) = Store : &:r42_6, r42_5 +# 43| r43_1(glval<_Imaginary float>) = VariableAddress[jf1] : +# 43| r43_2(_Imaginary float) = Load : &:r43_1, ~mu14_4 +# 43| r43_3(glval<_Imaginary float>) = VariableAddress[jf2] : +# 43| r43_4(_Imaginary float) = Load : &:r43_3, ~mu14_4 +# 43| r43_5(float) = Div : r43_2, r43_4 +# 43| r43_6(glval) = VariableAddress[f3] : +# 43| mu43_7(float) = Store : &:r43_6, r43_5 +# 46| r46_1(glval<_Imaginary float>) = VariableAddress[jf1] : +# 46| r46_2(_Imaginary float) = Load : &:r46_1, ~mu14_4 +# 46| r46_3(glval) = VariableAddress[f2] : +# 46| r46_4(float) = Load : &:r46_3, ~mu14_4 +# 46| r46_5(_Complex float) = Add : r46_2, r46_4 +# 46| r46_6(glval<_Complex float>) = VariableAddress[cf3] : +# 46| mu46_7(_Complex float) = Store : &:r46_6, r46_5 +# 47| r47_1(glval<_Imaginary float>) = VariableAddress[jf1] : +# 47| r47_2(_Imaginary float) = Load : &:r47_1, ~mu14_4 +# 47| r47_3(glval) = VariableAddress[f2] : +# 47| r47_4(float) = Load : &:r47_3, ~mu14_4 +# 47| r47_5(_Complex float) = Sub : r47_2, r47_4 +# 47| r47_6(glval<_Complex float>) = VariableAddress[cf3] : +# 47| mu47_7(_Complex float) = Store : &:r47_6, r47_5 +# 48| r48_1(glval<_Imaginary float>) = VariableAddress[jf1] : +# 48| r48_2(_Imaginary float) = Load : &:r48_1, ~mu14_4 +# 48| r48_3(glval) = VariableAddress[f2] : +# 48| r48_4(float) = Load : &:r48_3, ~mu14_4 +# 48| r48_5(_Imaginary float) = Mul : r48_2, r48_4 +# 48| r48_6(glval<_Imaginary float>) = VariableAddress[jf3] : +# 48| mu48_7(_Imaginary float) = Store : &:r48_6, r48_5 +# 49| r49_1(glval<_Imaginary float>) = VariableAddress[jf1] : +# 49| r49_2(_Imaginary float) = Load : &:r49_1, ~mu14_4 +# 49| r49_3(glval) = VariableAddress[f2] : +# 49| r49_4(float) = Load : &:r49_3, ~mu14_4 +# 49| r49_5(_Imaginary float) = Div : r49_2, r49_4 +# 49| r49_6(glval<_Imaginary float>) = VariableAddress[jf3] : +# 49| mu49_7(_Imaginary float) = Store : &:r49_6, r49_5 +# 52| r52_1(glval) = VariableAddress[f1] : +# 52| r52_2(float) = Load : &:r52_1, ~mu14_4 +# 52| r52_3(glval<_Imaginary float>) = VariableAddress[jf2] : +# 52| r52_4(_Imaginary float) = Load : &:r52_3, ~mu14_4 +# 52| r52_5(_Complex float) = Add : r52_2, r52_4 +# 52| r52_6(glval<_Complex float>) = VariableAddress[cf3] : +# 52| mu52_7(_Complex float) = Store : &:r52_6, r52_5 +# 53| r53_1(glval) = VariableAddress[f1] : +# 53| r53_2(float) = Load : &:r53_1, ~mu14_4 +# 53| r53_3(glval<_Imaginary float>) = VariableAddress[jf2] : +# 53| r53_4(_Imaginary float) = Load : &:r53_3, ~mu14_4 +# 53| r53_5(_Complex float) = Sub : r53_2, r53_4 +# 53| r53_6(glval<_Complex float>) = VariableAddress[cf3] : +# 53| mu53_7(_Complex float) = Store : &:r53_6, r53_5 +# 54| r54_1(glval) = VariableAddress[f1] : +# 54| r54_2(float) = Load : &:r54_1, ~mu14_4 +# 54| r54_3(glval<_Imaginary float>) = VariableAddress[jf2] : +# 54| r54_4(_Imaginary float) = Load : &:r54_3, ~mu14_4 +# 54| r54_5(_Imaginary float) = Mul : r54_2, r54_4 +# 54| r54_6(glval<_Imaginary float>) = VariableAddress[jf3] : +# 54| mu54_7(_Imaginary float) = Store : &:r54_6, r54_5 +# 55| r55_1(glval) = VariableAddress[f1] : +# 55| r55_2(float) = Load : &:r55_1, ~mu14_4 +# 55| r55_3(glval<_Imaginary float>) = VariableAddress[jf2] : +# 55| r55_4(_Imaginary float) = Load : &:r55_3, ~mu14_4 +# 55| r55_5(_Imaginary float) = Div : r55_2, r55_4 +# 55| r55_6(glval<_Imaginary float>) = VariableAddress[jf3] : +# 55| mu55_7(_Imaginary float) = Store : &:r55_6, r55_5 +# 56| v56_1(void) = NoOp : +# 14| v14_5(void) = ReturnVoid : +# 14| v14_6(void) = UnmodeledUse : mu* +# 14| v14_7(void) = AliasedUse : ~mu14_4 +# 14| v14_8(void) = ExitFunction : + +# 58| void complex_conversions() +# 58| Block 0 +# 58| v58_1(void) = EnterFunction : +# 58| mu58_2(unknown) = AliasedDefinition : +# 58| mu58_3(unknown) = InitializeNonLocal : +# 58| mu58_4(unknown) = UnmodeledDefinition : +# 59| r59_1(glval) = VariableAddress[f] : +# 59| r59_2(float) = Constant[2.0] : +# 59| mu59_3(float) = Store : &:r59_1, r59_2 +# 60| r60_1(glval) = VariableAddress[d] : +# 60| r60_2(double) = Constant[3.0] : +# 60| mu60_3(double) = Store : &:r60_1, r60_2 +# 61| r61_1(glval) = VariableAddress[ld] : +# 61| r61_2(long double) = Constant[5.0] : +# 61| mu61_3(long double) = Store : &:r61_1, r61_2 +# 62| r62_1(glval<_Complex float>) = VariableAddress[cf] : +# 62| r62_2(double) = Constant[7.0] : +# 62| r62_3(_Complex float) = Convert : r62_2 +# 62| mu62_4(_Complex float) = Store : &:r62_1, r62_3 +# 63| r63_1(glval<_Complex double>) = VariableAddress[cd] : +# 63| r63_2(double) = Constant[11.0] : +# 63| r63_3(_Complex double) = Convert : r63_2 +# 63| mu63_4(_Complex double) = Store : &:r63_1, r63_3 +# 64| r64_1(glval<_Complex long double>) = VariableAddress[cld] : +# 64| r64_2(double) = Constant[13.0] : +# 64| r64_3(_Complex long double) = Convert : r64_2 +# 64| mu64_4(_Complex long double) = Store : &:r64_1, r64_3 +# 65| r65_1(glval<_Imaginary float>) = VariableAddress[jf] : +# 65| r65_2(_Imaginary float) = Constant[1.0i] : +# 65| mu65_3(_Imaginary float) = Store : &:r65_1, r65_2 +# 66| r66_1(glval<_Imaginary double>) = VariableAddress[jd] : +# 66| r66_2(_Imaginary float) = Constant[1.0i] : +# 66| r66_3(_Imaginary double) = Convert : r66_2 +# 66| mu66_4(_Imaginary double) = Store : &:r66_1, r66_3 +# 67| r67_1(glval<_Imaginary long double>) = VariableAddress[jld] : +# 67| r67_2(_Imaginary float) = Constant[1.0i] : +# 67| r67_3(_Imaginary long double) = Convert : r67_2 +# 67| mu67_4(_Imaginary long double) = Store : &:r67_1, r67_3 +# 70| r70_1(glval<_Complex float>) = VariableAddress[cf] : +# 70| r70_2(_Complex float) = Load : &:r70_1, ~mu58_4 +# 70| r70_3(glval<_Complex float>) = VariableAddress[cf] : +# 70| mu70_4(_Complex float) = Store : &:r70_3, r70_2 +# 71| r71_1(glval<_Complex double>) = VariableAddress[cd] : +# 71| r71_2(_Complex double) = Load : &:r71_1, ~mu58_4 +# 71| r71_3(_Complex float) = Convert : r71_2 +# 71| r71_4(glval<_Complex float>) = VariableAddress[cf] : +# 71| mu71_5(_Complex float) = Store : &:r71_4, r71_3 +# 72| r72_1(glval<_Complex long double>) = VariableAddress[cld] : +# 72| r72_2(_Complex long double) = Load : &:r72_1, ~mu58_4 +# 72| r72_3(_Complex float) = Convert : r72_2 +# 72| r72_4(glval<_Complex float>) = VariableAddress[cf] : +# 72| mu72_5(_Complex float) = Store : &:r72_4, r72_3 +# 73| r73_1(glval<_Complex float>) = VariableAddress[cf] : +# 73| r73_2(_Complex float) = Load : &:r73_1, ~mu58_4 +# 73| r73_3(_Complex double) = Convert : r73_2 +# 73| r73_4(glval<_Complex double>) = VariableAddress[cd] : +# 73| mu73_5(_Complex double) = Store : &:r73_4, r73_3 +# 74| r74_1(glval<_Complex double>) = VariableAddress[cd] : +# 74| r74_2(_Complex double) = Load : &:r74_1, ~mu58_4 +# 74| r74_3(glval<_Complex double>) = VariableAddress[cd] : +# 74| mu74_4(_Complex double) = Store : &:r74_3, r74_2 +# 75| r75_1(glval<_Complex long double>) = VariableAddress[cld] : +# 75| r75_2(_Complex long double) = Load : &:r75_1, ~mu58_4 +# 75| r75_3(_Complex double) = Convert : r75_2 +# 75| r75_4(glval<_Complex double>) = VariableAddress[cd] : +# 75| mu75_5(_Complex double) = Store : &:r75_4, r75_3 +# 76| r76_1(glval<_Complex float>) = VariableAddress[cf] : +# 76| r76_2(_Complex float) = Load : &:r76_1, ~mu58_4 +# 76| r76_3(_Complex long double) = Convert : r76_2 +# 76| r76_4(glval<_Complex long double>) = VariableAddress[cld] : +# 76| mu76_5(_Complex long double) = Store : &:r76_4, r76_3 +# 77| r77_1(glval<_Complex double>) = VariableAddress[cd] : +# 77| r77_2(_Complex double) = Load : &:r77_1, ~mu58_4 +# 77| r77_3(_Complex long double) = Convert : r77_2 +# 77| r77_4(glval<_Complex long double>) = VariableAddress[cld] : +# 77| mu77_5(_Complex long double) = Store : &:r77_4, r77_3 +# 78| r78_1(glval<_Complex long double>) = VariableAddress[cld] : +# 78| r78_2(_Complex long double) = Load : &:r78_1, ~mu58_4 +# 78| r78_3(glval<_Complex long double>) = VariableAddress[cld] : +# 78| mu78_4(_Complex long double) = Store : &:r78_3, r78_2 +# 81| r81_1(glval) = VariableAddress[f] : +# 81| r81_2(float) = Load : &:r81_1, ~mu58_4 +# 81| r81_3(_Complex float) = Convert : r81_2 +# 81| r81_4(glval<_Complex float>) = VariableAddress[cf] : +# 81| mu81_5(_Complex float) = Store : &:r81_4, r81_3 +# 82| r82_1(glval) = VariableAddress[d] : +# 82| r82_2(double) = Load : &:r82_1, ~mu58_4 +# 82| r82_3(_Complex float) = Convert : r82_2 +# 82| r82_4(glval<_Complex float>) = VariableAddress[cf] : +# 82| mu82_5(_Complex float) = Store : &:r82_4, r82_3 +# 83| r83_1(glval) = VariableAddress[ld] : +# 83| r83_2(long double) = Load : &:r83_1, ~mu58_4 +# 83| r83_3(_Complex float) = Convert : r83_2 +# 83| r83_4(glval<_Complex float>) = VariableAddress[cf] : +# 83| mu83_5(_Complex float) = Store : &:r83_4, r83_3 +# 84| r84_1(glval) = VariableAddress[f] : +# 84| r84_2(float) = Load : &:r84_1, ~mu58_4 +# 84| r84_3(_Complex double) = Convert : r84_2 +# 84| r84_4(glval<_Complex double>) = VariableAddress[cd] : +# 84| mu84_5(_Complex double) = Store : &:r84_4, r84_3 +# 85| r85_1(glval) = VariableAddress[d] : +# 85| r85_2(double) = Load : &:r85_1, ~mu58_4 +# 85| r85_3(_Complex double) = Convert : r85_2 +# 85| r85_4(glval<_Complex double>) = VariableAddress[cd] : +# 85| mu85_5(_Complex double) = Store : &:r85_4, r85_3 +# 86| r86_1(glval) = VariableAddress[ld] : +# 86| r86_2(long double) = Load : &:r86_1, ~mu58_4 +# 86| r86_3(_Complex double) = Convert : r86_2 +# 86| r86_4(glval<_Complex double>) = VariableAddress[cd] : +# 86| mu86_5(_Complex double) = Store : &:r86_4, r86_3 +# 87| r87_1(glval) = VariableAddress[f] : +# 87| r87_2(float) = Load : &:r87_1, ~mu58_4 +# 87| r87_3(_Complex long double) = Convert : r87_2 +# 87| r87_4(glval<_Complex long double>) = VariableAddress[cld] : +# 87| mu87_5(_Complex long double) = Store : &:r87_4, r87_3 +# 88| r88_1(glval) = VariableAddress[d] : +# 88| r88_2(double) = Load : &:r88_1, ~mu58_4 +# 88| r88_3(_Complex long double) = Convert : r88_2 +# 88| r88_4(glval<_Complex long double>) = VariableAddress[cld] : +# 88| mu88_5(_Complex long double) = Store : &:r88_4, r88_3 +# 89| r89_1(glval) = VariableAddress[ld] : +# 89| r89_2(long double) = Load : &:r89_1, ~mu58_4 +# 89| r89_3(_Complex long double) = Convert : r89_2 +# 89| r89_4(glval<_Complex long double>) = VariableAddress[cld] : +# 89| mu89_5(_Complex long double) = Store : &:r89_4, r89_3 +# 92| r92_1(glval<_Complex float>) = VariableAddress[cf] : +# 92| r92_2(_Complex float) = Load : &:r92_1, ~mu58_4 +# 92| r92_3(float) = Convert : r92_2 +# 92| r92_4(glval) = VariableAddress[f] : +# 92| mu92_5(float) = Store : &:r92_4, r92_3 +# 93| r93_1(glval<_Complex double>) = VariableAddress[cd] : +# 93| r93_2(_Complex double) = Load : &:r93_1, ~mu58_4 +# 93| r93_3(float) = Convert : r93_2 +# 93| r93_4(glval) = VariableAddress[f] : +# 93| mu93_5(float) = Store : &:r93_4, r93_3 +# 94| r94_1(glval<_Complex long double>) = VariableAddress[cld] : +# 94| r94_2(_Complex long double) = Load : &:r94_1, ~mu58_4 +# 94| r94_3(float) = Convert : r94_2 +# 94| r94_4(glval) = VariableAddress[f] : +# 94| mu94_5(float) = Store : &:r94_4, r94_3 +# 95| r95_1(glval<_Complex float>) = VariableAddress[cf] : +# 95| r95_2(_Complex float) = Load : &:r95_1, ~mu58_4 +# 95| r95_3(double) = Convert : r95_2 +# 95| r95_4(glval) = VariableAddress[d] : +# 95| mu95_5(double) = Store : &:r95_4, r95_3 +# 96| r96_1(glval<_Complex double>) = VariableAddress[cd] : +# 96| r96_2(_Complex double) = Load : &:r96_1, ~mu58_4 +# 96| r96_3(double) = Convert : r96_2 +# 96| r96_4(glval) = VariableAddress[d] : +# 96| mu96_5(double) = Store : &:r96_4, r96_3 +# 97| r97_1(glval<_Complex long double>) = VariableAddress[cld] : +# 97| r97_2(_Complex long double) = Load : &:r97_1, ~mu58_4 +# 97| r97_3(double) = Convert : r97_2 +# 97| r97_4(glval) = VariableAddress[d] : +# 97| mu97_5(double) = Store : &:r97_4, r97_3 +# 98| r98_1(glval<_Complex float>) = VariableAddress[cf] : +# 98| r98_2(_Complex float) = Load : &:r98_1, ~mu58_4 +# 98| r98_3(long double) = Convert : r98_2 +# 98| r98_4(glval) = VariableAddress[ld] : +# 98| mu98_5(long double) = Store : &:r98_4, r98_3 +# 99| r99_1(glval<_Complex double>) = VariableAddress[cd] : +# 99| r99_2(_Complex double) = Load : &:r99_1, ~mu58_4 +# 99| r99_3(long double) = Convert : r99_2 +# 99| r99_4(glval) = VariableAddress[ld] : +# 99| mu99_5(long double) = Store : &:r99_4, r99_3 +# 100| r100_1(glval<_Complex long double>) = VariableAddress[cld] : +# 100| r100_2(_Complex long double) = Load : &:r100_1, ~mu58_4 +# 100| r100_3(long double) = Convert : r100_2 +# 100| r100_4(glval) = VariableAddress[ld] : +# 100| mu100_5(long double) = Store : &:r100_4, r100_3 +# 103| r103_1(glval<_Imaginary float>) = VariableAddress[jf] : +# 103| r103_2(_Imaginary float) = Load : &:r103_1, ~mu58_4 +# 103| r103_3(_Complex float) = Convert : r103_2 +# 103| r103_4(glval<_Complex float>) = VariableAddress[cf] : +# 103| mu103_5(_Complex float) = Store : &:r103_4, r103_3 +# 104| r104_1(glval<_Imaginary double>) = VariableAddress[jd] : +# 104| r104_2(_Imaginary double) = Load : &:r104_1, ~mu58_4 +# 104| r104_3(_Complex float) = Convert : r104_2 +# 104| r104_4(glval<_Complex float>) = VariableAddress[cf] : +# 104| mu104_5(_Complex float) = Store : &:r104_4, r104_3 +# 105| r105_1(glval<_Imaginary long double>) = VariableAddress[jld] : +# 105| r105_2(_Imaginary long double) = Load : &:r105_1, ~mu58_4 +# 105| r105_3(_Complex float) = Convert : r105_2 +# 105| r105_4(glval<_Complex float>) = VariableAddress[cf] : +# 105| mu105_5(_Complex float) = Store : &:r105_4, r105_3 +# 106| r106_1(glval<_Imaginary float>) = VariableAddress[jf] : +# 106| r106_2(_Imaginary float) = Load : &:r106_1, ~mu58_4 +# 106| r106_3(_Complex double) = Convert : r106_2 +# 106| r106_4(glval<_Complex double>) = VariableAddress[cd] : +# 106| mu106_5(_Complex double) = Store : &:r106_4, r106_3 +# 107| r107_1(glval<_Imaginary double>) = VariableAddress[jd] : +# 107| r107_2(_Imaginary double) = Load : &:r107_1, ~mu58_4 +# 107| r107_3(_Complex double) = Convert : r107_2 +# 107| r107_4(glval<_Complex double>) = VariableAddress[cd] : +# 107| mu107_5(_Complex double) = Store : &:r107_4, r107_3 +# 108| r108_1(glval<_Imaginary long double>) = VariableAddress[jld] : +# 108| r108_2(_Imaginary long double) = Load : &:r108_1, ~mu58_4 +# 108| r108_3(_Complex double) = Convert : r108_2 +# 108| r108_4(glval<_Complex double>) = VariableAddress[cd] : +# 108| mu108_5(_Complex double) = Store : &:r108_4, r108_3 +# 109| r109_1(glval<_Imaginary float>) = VariableAddress[jf] : +# 109| r109_2(_Imaginary float) = Load : &:r109_1, ~mu58_4 +# 109| r109_3(_Complex long double) = Convert : r109_2 +# 109| r109_4(glval<_Complex long double>) = VariableAddress[cld] : +# 109| mu109_5(_Complex long double) = Store : &:r109_4, r109_3 +# 110| r110_1(glval<_Imaginary double>) = VariableAddress[jd] : +# 110| r110_2(_Imaginary double) = Load : &:r110_1, ~mu58_4 +# 110| r110_3(_Complex long double) = Convert : r110_2 +# 110| r110_4(glval<_Complex long double>) = VariableAddress[cld] : +# 110| mu110_5(_Complex long double) = Store : &:r110_4, r110_3 +# 111| r111_1(glval<_Imaginary long double>) = VariableAddress[jld] : +# 111| r111_2(_Imaginary long double) = Load : &:r111_1, ~mu58_4 +# 111| r111_3(_Complex long double) = Convert : r111_2 +# 111| r111_4(glval<_Complex long double>) = VariableAddress[cld] : +# 111| mu111_5(_Complex long double) = Store : &:r111_4, r111_3 +# 114| r114_1(glval<_Complex float>) = VariableAddress[cf] : +# 114| r114_2(_Complex float) = Load : &:r114_1, ~mu58_4 +# 114| r114_3(_Imaginary float) = Convert : r114_2 +# 114| r114_4(glval<_Imaginary float>) = VariableAddress[jf] : +# 114| mu114_5(_Imaginary float) = Store : &:r114_4, r114_3 +# 115| r115_1(glval<_Complex double>) = VariableAddress[cd] : +# 115| r115_2(_Complex double) = Load : &:r115_1, ~mu58_4 +# 115| r115_3(_Imaginary float) = Convert : r115_2 +# 115| r115_4(glval<_Imaginary float>) = VariableAddress[jf] : +# 115| mu115_5(_Imaginary float) = Store : &:r115_4, r115_3 +# 116| r116_1(glval<_Complex long double>) = VariableAddress[cld] : +# 116| r116_2(_Complex long double) = Load : &:r116_1, ~mu58_4 +# 116| r116_3(_Imaginary float) = Convert : r116_2 +# 116| r116_4(glval<_Imaginary float>) = VariableAddress[jf] : +# 116| mu116_5(_Imaginary float) = Store : &:r116_4, r116_3 +# 117| r117_1(glval<_Complex float>) = VariableAddress[cf] : +# 117| r117_2(_Complex float) = Load : &:r117_1, ~mu58_4 +# 117| r117_3(_Imaginary double) = Convert : r117_2 +# 117| r117_4(glval<_Imaginary double>) = VariableAddress[jd] : +# 117| mu117_5(_Imaginary double) = Store : &:r117_4, r117_3 +# 118| r118_1(glval<_Complex double>) = VariableAddress[cd] : +# 118| r118_2(_Complex double) = Load : &:r118_1, ~mu58_4 +# 118| r118_3(_Imaginary double) = Convert : r118_2 +# 118| r118_4(glval<_Imaginary double>) = VariableAddress[jd] : +# 118| mu118_5(_Imaginary double) = Store : &:r118_4, r118_3 +# 119| r119_1(glval<_Complex long double>) = VariableAddress[cld] : +# 119| r119_2(_Complex long double) = Load : &:r119_1, ~mu58_4 +# 119| r119_3(_Imaginary double) = Convert : r119_2 +# 119| r119_4(glval<_Imaginary double>) = VariableAddress[jd] : +# 119| mu119_5(_Imaginary double) = Store : &:r119_4, r119_3 +# 120| r120_1(glval<_Complex float>) = VariableAddress[cf] : +# 120| r120_2(_Complex float) = Load : &:r120_1, ~mu58_4 +# 120| r120_3(_Imaginary long double) = Convert : r120_2 +# 120| r120_4(glval<_Imaginary long double>) = VariableAddress[jld] : +# 120| mu120_5(_Imaginary long double) = Store : &:r120_4, r120_3 +# 121| r121_1(glval<_Complex double>) = VariableAddress[cd] : +# 121| r121_2(_Complex double) = Load : &:r121_1, ~mu58_4 +# 121| r121_3(_Imaginary long double) = Convert : r121_2 +# 121| r121_4(glval<_Imaginary long double>) = VariableAddress[jld] : +# 121| mu121_5(_Imaginary long double) = Store : &:r121_4, r121_3 +# 122| r122_1(glval<_Complex long double>) = VariableAddress[cld] : +# 122| r122_2(_Complex long double) = Load : &:r122_1, ~mu58_4 +# 122| r122_3(_Imaginary long double) = Convert : r122_2 +# 122| r122_4(glval<_Imaginary long double>) = VariableAddress[jld] : +# 122| mu122_5(_Imaginary long double) = Store : &:r122_4, r122_3 +# 125| r125_1(glval) = VariableAddress[f] : +# 125| r125_2(float) = Load : &:r125_1, ~mu58_4 +# 125| r125_3(_Imaginary float) = Convert : r125_2 +# 125| r125_4(glval<_Imaginary float>) = VariableAddress[jf] : +# 125| mu125_5(_Imaginary float) = Store : &:r125_4, r125_3 +# 126| r126_1(glval) = VariableAddress[d] : +# 126| r126_2(double) = Load : &:r126_1, ~mu58_4 +# 126| r126_3(_Imaginary float) = Convert : r126_2 +# 126| r126_4(glval<_Imaginary float>) = VariableAddress[jf] : +# 126| mu126_5(_Imaginary float) = Store : &:r126_4, r126_3 +# 127| r127_1(glval) = VariableAddress[ld] : +# 127| r127_2(long double) = Load : &:r127_1, ~mu58_4 +# 127| r127_3(_Imaginary float) = Convert : r127_2 +# 127| r127_4(glval<_Imaginary float>) = VariableAddress[jf] : +# 127| mu127_5(_Imaginary float) = Store : &:r127_4, r127_3 +# 128| r128_1(glval) = VariableAddress[f] : +# 128| r128_2(float) = Load : &:r128_1, ~mu58_4 +# 128| r128_3(_Imaginary double) = Convert : r128_2 +# 128| r128_4(glval<_Imaginary double>) = VariableAddress[jd] : +# 128| mu128_5(_Imaginary double) = Store : &:r128_4, r128_3 +# 129| r129_1(glval) = VariableAddress[d] : +# 129| r129_2(double) = Load : &:r129_1, ~mu58_4 +# 129| r129_3(_Imaginary double) = Convert : r129_2 +# 129| r129_4(glval<_Imaginary double>) = VariableAddress[jd] : +# 129| mu129_5(_Imaginary double) = Store : &:r129_4, r129_3 +# 130| r130_1(glval) = VariableAddress[ld] : +# 130| r130_2(long double) = Load : &:r130_1, ~mu58_4 +# 130| r130_3(_Imaginary double) = Convert : r130_2 +# 130| r130_4(glval<_Imaginary double>) = VariableAddress[jd] : +# 130| mu130_5(_Imaginary double) = Store : &:r130_4, r130_3 +# 131| r131_1(glval) = VariableAddress[f] : +# 131| r131_2(float) = Load : &:r131_1, ~mu58_4 +# 131| r131_3(_Imaginary long double) = Convert : r131_2 +# 131| r131_4(glval<_Imaginary long double>) = VariableAddress[jld] : +# 131| mu131_5(_Imaginary long double) = Store : &:r131_4, r131_3 +# 132| r132_1(glval) = VariableAddress[d] : +# 132| r132_2(double) = Load : &:r132_1, ~mu58_4 +# 132| r132_3(_Imaginary long double) = Convert : r132_2 +# 132| r132_4(glval<_Imaginary long double>) = VariableAddress[jld] : +# 132| mu132_5(_Imaginary long double) = Store : &:r132_4, r132_3 +# 133| r133_1(glval) = VariableAddress[ld] : +# 133| r133_2(long double) = Load : &:r133_1, ~mu58_4 +# 133| r133_3(_Imaginary long double) = Convert : r133_2 +# 133| r133_4(glval<_Imaginary long double>) = VariableAddress[jld] : +# 133| mu133_5(_Imaginary long double) = Store : &:r133_4, r133_3 +# 136| r136_1(glval<_Imaginary float>) = VariableAddress[jf] : +# 136| r136_2(_Imaginary float) = Load : &:r136_1, ~mu58_4 +# 136| r136_3(float) = Convert : r136_2 +# 136| r136_4(glval) = VariableAddress[f] : +# 136| mu136_5(float) = Store : &:r136_4, r136_3 +# 137| r137_1(glval<_Imaginary double>) = VariableAddress[jd] : +# 137| r137_2(_Imaginary double) = Load : &:r137_1, ~mu58_4 +# 137| r137_3(float) = Convert : r137_2 +# 137| r137_4(glval) = VariableAddress[f] : +# 137| mu137_5(float) = Store : &:r137_4, r137_3 +# 138| r138_1(glval<_Imaginary long double>) = VariableAddress[jld] : +# 138| r138_2(_Imaginary long double) = Load : &:r138_1, ~mu58_4 +# 138| r138_3(float) = Convert : r138_2 +# 138| r138_4(glval) = VariableAddress[f] : +# 138| mu138_5(float) = Store : &:r138_4, r138_3 +# 139| r139_1(glval<_Imaginary float>) = VariableAddress[jf] : +# 139| r139_2(_Imaginary float) = Load : &:r139_1, ~mu58_4 +# 139| r139_3(double) = Convert : r139_2 +# 139| r139_4(glval) = VariableAddress[d] : +# 139| mu139_5(double) = Store : &:r139_4, r139_3 +# 140| r140_1(glval<_Imaginary double>) = VariableAddress[jd] : +# 140| r140_2(_Imaginary double) = Load : &:r140_1, ~mu58_4 +# 140| r140_3(double) = Convert : r140_2 +# 140| r140_4(glval) = VariableAddress[d] : +# 140| mu140_5(double) = Store : &:r140_4, r140_3 +# 141| r141_1(glval<_Imaginary long double>) = VariableAddress[jld] : +# 141| r141_2(_Imaginary long double) = Load : &:r141_1, ~mu58_4 +# 141| r141_3(double) = Convert : r141_2 +# 141| r141_4(glval) = VariableAddress[d] : +# 141| mu141_5(double) = Store : &:r141_4, r141_3 +# 142| r142_1(glval<_Imaginary float>) = VariableAddress[jf] : +# 142| r142_2(_Imaginary float) = Load : &:r142_1, ~mu58_4 +# 142| r142_3(long double) = Convert : r142_2 +# 142| r142_4(glval) = VariableAddress[ld] : +# 142| mu142_5(long double) = Store : &:r142_4, r142_3 +# 143| r143_1(glval<_Imaginary double>) = VariableAddress[jd] : +# 143| r143_2(_Imaginary double) = Load : &:r143_1, ~mu58_4 +# 143| r143_3(long double) = Convert : r143_2 +# 143| r143_4(glval) = VariableAddress[ld] : +# 143| mu143_5(long double) = Store : &:r143_4, r143_3 +# 144| r144_1(glval<_Imaginary long double>) = VariableAddress[jld] : +# 144| r144_2(_Imaginary long double) = Load : &:r144_1, ~mu58_4 +# 144| r144_3(long double) = Convert : r144_2 +# 144| r144_4(glval) = VariableAddress[ld] : +# 144| mu144_5(long double) = Store : &:r144_4, r144_3 +# 145| v145_1(void) = NoOp : +# 58| v58_5(void) = ReturnVoid : +# 58| v58_6(void) = UnmodeledUse : mu* +# 58| v58_7(void) = AliasedUse : ~mu58_4 +# 58| v58_8(void) = ExitFunction : ir.cpp: # 1| void Constants() diff --git a/cpp/ql/test/library-tests/ir/types/complex.c b/cpp/ql/test/library-tests/ir/types/complex.c index 3766bde086a..450f5de9e65 100644 --- a/cpp/ql/test/library-tests/ir/types/complex.c +++ b/cpp/ql/test/library-tests/ir/types/complex.c @@ -2,5 +2,14 @@ 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 + // _Complex __float128 cf128; +} + +void Imaginary(void) { + _Imaginary float jf; //$irtype=ifloat4 + _Imaginary double jd; //$irtype=ifloat8 + _Imaginary long double jld; //$irtype=ifloat16 + // _Imaginary __float128 jf128; +} + +// semmle-extractor-options: --microsoft --edg --c99 From ea0f6a367deb9ed2d250b4ca22803b129913d3e0 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 17 Apr 2020 09:50:08 +0200 Subject: [PATCH 0161/1298] refactor into maybePromisified predicate --- .../javascript/frameworks/NodeJSLib.qll | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll index bf343b28603..d2f5bea3b65 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll @@ -586,6 +586,19 @@ module NodeJSLib { } } + /** + * Gets a possibly promisified (using `util.promisify`) version of the input `func`. + */ + DataFlow::SourceNode maybePromisified(DataFlow::SourceNode func) { + result = func + or + exists(DataFlow::CallNode promisify | + promisify = DataFlow::moduleMember("util", "promisify").getACall() + | + result = promisify and promisify.getArgument(0).getALocalSource() = func + ) + } + /** * A call to a method from module `child_process`. */ @@ -593,15 +606,7 @@ module NodeJSLib { string methodName; ChildProcessMethodCall() { - this = DataFlow::moduleMember("child_process", methodName).getACall() - or - exists(DataFlow::CallNode promisify | - promisify = DataFlow::moduleMember("util", "promisify").getACall() - | - this = promisify.getACall() and - promisify.getArgument(0).getALocalSource() = - DataFlow::moduleMember("child_process", methodName) - ) + this = maybePromisified(DataFlow::moduleMember("child_process", methodName)).getACall() } private DataFlow::Node getACommandArgument(boolean shell) { From eca98b42d212e06684fd7c20635cfcf848fd611e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 17 Apr 2020 09:54:37 +0200 Subject: [PATCH 0162/1298] basic support for util.promisify for NodeJSFileSystemAccess --- .../javascript/frameworks/NodeJSLib.qll | 2 +- .../CWE-022/TaintedPath/TaintedPath.expected | 199 ++++++++++++++++++ .../CWE-022/TaintedPath/other-fs-libraries.js | 8 + 3 files changed, 208 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll index d2f5bea3b65..3437aa09830 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll @@ -459,7 +459,7 @@ module NodeJSLib { private class NodeJSFileSystemAccess extends FileSystemAccess, DataFlow::CallNode { string methodName; - NodeJSFileSystemAccess() { this = fsModuleMember(methodName).getACall() } + NodeJSFileSystemAccess() { this = maybePromisified(fsModuleMember(methodName)).getACall() } /** * Gets the name of the called method. diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected index fb4fcb3503e..914c2099868 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected @@ -2082,6 +2082,92 @@ nodes | other-fs-libraries.js:24:35:24:38 | path | | other-fs-libraries.js:24:35:24:38 | path | | other-fs-libraries.js:24:35:24:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:24:38:30 | req.url | +| other-fs-libraries.js:38:24:38:30 | req.url | +| other-fs-libraries.js:38:24:38:30 | req.url | +| other-fs-libraries.js:38:24:38:30 | req.url | +| other-fs-libraries.js:38:24:38:30 | req.url | +| other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:40:35:40:38 | path | | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-require.js:7:19:7:37 | req.param("module") | @@ -5673,6 +5759,118 @@ edges | other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:9:14:9:37 | url.par ... , true) | | other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:9:14:9:37 | url.par ... , true) | | other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:9:14:9:37 | url.par ... , true) | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | @@ -6572,6 +6770,7 @@ edges | other-fs-libraries.js:17:35:17:38 | path | other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:17:35:17:38 | path | This path depends on $@. | other-fs-libraries.js:9:24:9:30 | req.url | a user-provided value | | other-fs-libraries.js:19:56:19:59 | path | other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:19:56:19:59 | path | This path depends on $@. | other-fs-libraries.js:9:24:9:30 | req.url | a user-provided value | | other-fs-libraries.js:24:35:24:38 | path | other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:24:35:24:38 | path | This path depends on $@. | other-fs-libraries.js:9:24:9:30 | req.url | a user-provided value | +| other-fs-libraries.js:40:35:40:38 | path | other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:40:35:40:38 | path | This path depends on $@. | other-fs-libraries.js:38:24:38:30 | req.url | a user-provided value | | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | This path depends on $@. | tainted-require.js:7:19:7:37 | req.param("module") | a user-provided value | | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | a user-provided value | | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/other-fs-libraries.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/other-fs-libraries.js index 611aac86f30..5eb1d0d6524 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/other-fs-libraries.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/other-fs-libraries.js @@ -31,3 +31,11 @@ function getFsModule(special) { return require("original-fs"); } } + +var util = require("util"); + +http.createServer(function(req, res) { + var path = url.parse(req.url, true).query.path; + + util.promisify(fs.readFileSync)(path); // NOT OK +}); \ No newline at end of file From 9191190248a4d0c190029898e298663ea490e737 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Fri, 17 Apr 2020 10:18:17 +0200 Subject: [PATCH 0163/1298] C++: Spaceship operator change note --- change-notes/1.24/analysis-cpp.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/change-notes/1.24/analysis-cpp.md b/change-notes/1.24/analysis-cpp.md index 78e86c29c31..75af90b45bd 100644 --- a/change-notes/1.24/analysis-cpp.md +++ b/change-notes/1.24/analysis-cpp.md @@ -35,6 +35,9 @@ The following changes in version 1.24 affect C/C++ analysis in all applications. ## Changes to libraries +* The built-in C++20 "spaceship operator" (`<=>`) is now supported via the QL + class `SpaceshipExpr`. Overloaded forms are modeled as calls to functions + named `operator<=>`. * The data-flow library has been improved, which affects and improves some security queries. The improvements are: - Track flow through functions that combine taint tracking with flow through fields. - Track flow through clone-like functions, that is, functions that read contents of a field from a From 7dab89ef5601a4b8c66e53a782169ea4995c7d92 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Fri, 17 Apr 2020 10:32:28 +0200 Subject: [PATCH 0164/1298] C++: More details about lib implementation changes This commit mostly restores the previous note about library changes but avoids mentioning queries in the library section. --- change-notes/1.24/analysis-cpp.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/change-notes/1.24/analysis-cpp.md b/change-notes/1.24/analysis-cpp.md index 75af90b45bd..b9a7cdc96a0 100644 --- a/change-notes/1.24/analysis-cpp.md +++ b/change-notes/1.24/analysis-cpp.md @@ -38,10 +38,21 @@ The following changes in version 1.24 affect C/C++ analysis in all applications. * The built-in C++20 "spaceship operator" (`<=>`) is now supported via the QL class `SpaceshipExpr`. Overloaded forms are modeled as calls to functions named `operator<=>`. -* The data-flow library has been improved, which affects and improves some security queries. The improvements are: +* The data-flow library (`semmle.code.cpp.dataflow.DataFlow` and + `semmle.code.cpp.dataflow.TaintTracking`) has been improved, which affects + and improves some security queries. The improvements are: - Track flow through functions that combine taint tracking with flow through fields. - Track flow through clone-like functions, that is, functions that read contents of a field from a parameter and stores the value in the field of a returned object. +* The security pack taint tracking library + (`semmle.code.cpp.security.TaintTracking`) uses a new intermediate + representation. This provides a more precise analysis of flow through + parameters and pointers. For new queries, however, we continue to recommend + using `semmle.code.cpp.dataflow.TaintTracking`. +* The global value numbering library + (`semmle.code.cpp.valuenumbering.GlobalValueNumbering`) uses a new + intermediate representation to provide a more precise analysis of + heap-allocated memory and pointers to stack variables. * Created the `semmle.code.cpp.models.interfaces.Allocation` library to model allocation such as `new` expressions and calls to `malloc`. This in intended to replace the functionality in `semmle.code.cpp.commons.Alloc` with a more From dd9aec056c7266274fb8df5cf2a787a1595b7fdf Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 3 Apr 2020 11:47:53 +0200 Subject: [PATCH 0165/1298] handle basic dynamic method dispatch for jQuery methods --- javascript/ql/src/semmle/javascript/frameworks/jQuery.qll | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/jQuery.qll b/javascript/ql/src/semmle/javascript/frameworks/jQuery.qll index 82a78d3df79..e814610ac5f 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/jQuery.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/jQuery.qll @@ -538,9 +538,13 @@ module JQuery { MethodCall() { this = dollarCall() and name = "$" or - this = dollar().getAMemberCall(name) + this = ([dollar(), objectRef()]).getAMemberCall(name) or - this = objectRef().getAMethodCall(name) + // Handle basic dynamic method dispatch (e.g. `$element[html ? 'html' : 'text'](content)`) + exists(DataFlow::PropRead read | read = this.getCalleeNode() | + read.getBase().getALocalSource() = [dollar(), objectRef()] and + read.getPropertyNameExpr().flow().mayHaveStringValue(name) + ) or // Handle contributed JQuery objects that aren't source nodes (usually parameter uses) getReceiver() = legacyObjectSource() and From 55edfed1ee0a03aa8d03836afb420896a58bd930 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 3 Apr 2020 11:48:10 +0200 Subject: [PATCH 0166/1298] support jQuery().get() returning a DOM node --- javascript/ql/src/semmle/javascript/DOM.qll | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/DOM.qll b/javascript/ql/src/semmle/javascript/DOM.qll index 71f0239ed27..fcce5a4759f 100644 --- a/javascript/ql/src/semmle/javascript/DOM.qll +++ b/javascript/ql/src/semmle/javascript/DOM.qll @@ -4,6 +4,7 @@ import javascript import semmle.javascript.frameworks.Templating +private import semmle.javascript.dataflow.InferredTypes module DOM { /** @@ -292,10 +293,18 @@ module DOM { private class DefaultRange extends Range { DefaultRange() { - this.asExpr().(VarAccess).getVariable() instanceof DOMGlobalVariable or - this = domValueRef().getAPropertyRead() or - this = domElementCreationOrQuery() or + this.asExpr().(VarAccess).getVariable() instanceof DOMGlobalVariable + or + this = domValueRef().getAPropertyRead() + or + this = domElementCreationOrQuery() + or this = domElementCollection() + or + exists(JQuery::MethodCall call | this = call and call.getMethodName() = "get" | + call.getNumArgument() = 1 and + forex(InferredType t | t = call.getArgument(0).analyze().getAType() | t = TTNumber()) + ) } } } From 14b551f887c61c9e654ba7250a0c49d203e2f421 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 3 Apr 2020 11:48:25 +0200 Subject: [PATCH 0167/1298] Xss through DOM --- .../ql/src/Security/CWE-079/XssThroughDom.ql | 21 +++ .../javascript/security/dataflow/Xss.qll | 6 + .../security/dataflow/XssThroughDom.qll | 141 ++++++++++++++++++ .../Security/CWE-079/XssThroughDom.expected | 63 ++++++++ .../Security/CWE-079/XssThroughDom.qlref | 1 + .../Security/CWE-079/xss-through-dom.js | 62 ++++++++ 6 files changed, 294 insertions(+) create mode 100644 javascript/ql/src/Security/CWE-079/XssThroughDom.ql create mode 100644 javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll create mode 100644 javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-079/xss-through-dom.js diff --git a/javascript/ql/src/Security/CWE-079/XssThroughDom.ql b/javascript/ql/src/Security/CWE-079/XssThroughDom.ql new file mode 100644 index 00000000000..a87ed4955a2 --- /dev/null +++ b/javascript/ql/src/Security/CWE-079/XssThroughDom.ql @@ -0,0 +1,21 @@ +/** + * @name Cross-site scripting through DOM + * @description Writing user controlled DOM to HTML can allow for + * a cross-site scripting vulnerability. + * @kind path-problem + * @problem.severity error + * @precision medium + * @id js/xss-through-dom + * @tags security + * external/cwe/cwe-079 + * external/cwe/cwe-116 + */ + +import javascript +import semmle.javascript.security.dataflow.XssThroughDom::XssThroughDom +import DataFlow::PathGraph + +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Cross-site scripting vulnerability due to $@.", + source.getNode(), "DOM text" diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll index 47aff96c9c3..98dcb59992f 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll @@ -413,3 +413,9 @@ module StoredXss { private class UriEncodingSanitizer extends Sanitizer, Shared::UriEncodingSanitizer { } } + +/** Provides classes and predicates for the XSS through DOM query. */ +module XssThroughDom { + /** A data flow source for XSS through DOM vulnerabilities. */ + abstract class Source extends Shared::Source { } +} diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll b/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll new file mode 100644 index 00000000000..36e735283a3 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll @@ -0,0 +1,141 @@ +/** + * Provides a taint-tracking configuration for reasoning about + * cross-site scripting vulnerabilities through the DOM. + */ + +import javascript + +/** + * Classes and predicates for the XSS through DOM query. + */ +module XssThroughDom { + import Xss::XssThroughDom + private import semmle.javascript.security.dataflow.Xss::DomBasedXss as DomBasedXss + private import semmle.javascript.dataflow.InferredTypes + + /** + * A taint-tracking configuration for reasoning about XSS through the DOM. + */ + class Configuration extends TaintTracking::Configuration { + Configuration() { this = "XssThroughDOM" } + + override predicate isSource(DataFlow::Node source) { source instanceof Source } + + override predicate isSink(DataFlow::Node sink) { sink instanceof DomBasedXss::Sink } + + override predicate isSanitizer(DataFlow::Node node) { + super.isSanitizer(node) or + node instanceof DomBasedXss::Sanitizer + } + + override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) { + guard instanceof TypeTestGuard or + guard instanceof HasNodePropertySanitizerGuard + } + } + + /** + * Gets an attribute name that could store user controlled data. + * + * Attributes such as "id", "href", and "src" are often used as input to HTML. + * However, they are either rarely controlable by a user, or already a sink for other XSS vulnerabilities. + * Such attributes are therefore ignored. + */ + bindingset[result] + string unsafeAttributeName() { + result.regexpMatch("data-.*") or + result = ["name", "value"] + } + + /** + * A source for text from the DOM from a JQuery method call. + */ + class JQueryTextSource extends Source, JQuery::MethodCall { + JQueryTextSource() { + ( + this.getMethodName() = ["text", "val"] and this.getNumArgument() = 0 + or + this.getMethodName() = "attr" and + this.getNumArgument() = 1 and + forex(InferredType t | t = this.getArgument(0).analyze().getAType() | t = TTString()) and + this.getArgument(0).mayHaveStringValue(unsafeAttributeName()) + ) and + // looks like a $("

    " + ... ) source, which is benign for this query. + not this + .getReceiver() + .(DataFlow::CallNode) + .getAnArgument() + .(StringOps::ConcatenationRoot) + .getConstantStringParts() + .substring(0, 1) = "<" + } + } + + /** + * A source for text from the DOM from a DOM property read or call to `getAttribute()`. + */ + class DOMTextSource extends Source { + DOMTextSource() { + exists(DataFlow::PropRead read | read = this | + read.getBase().getALocalSource() = DOM::domValueRef() and + exists(string propName | propName = ["innerText", "textContent", "value", "name"] | + read.getPropertyName() = propName or + read.getPropertyNameExpr().flow().mayHaveStringValue(propName) + ) + ) + or + exists(DataFlow::MethodCallNode mcn | mcn = this | + mcn.getReceiver().getALocalSource() = DOM::domValueRef() and + mcn.getMethodName() = "getAttribute" and + mcn.getArgument(0).mayHaveStringValue(unsafeAttributeName()) + ) + } + } + + /** + * A test of form `typeof x === "something"`, preventing `x` from being a string in some cases. + * + * This sanitizer helps prune infeasible paths in type-overloaded functions. + */ + class TypeTestGuard extends TaintTracking::SanitizerGuardNode, DataFlow::ValueNode { + override EqualityTest astNode; + TypeofExpr typeof; + boolean polarity; + + TypeTestGuard() { + astNode.getAnOperand() = typeof and + ( + // typeof x === "string" sanitizes `x` when it evaluates to false + astNode.getAnOperand().getStringValue() = "string" and + polarity = astNode.getPolarity().booleanNot() + or + // typeof x === "object" sanitizes `x` when it evaluates to true + astNode.getAnOperand().getStringValue() != "string" and + polarity = astNode.getPolarity() + ) + } + + override predicate sanitizes(boolean outcome, Expr e) { + polarity = outcome and + e = typeof.getOperand() + } + } + + /** + * The precense of a `nodeType` or `jquery` property indicates that the value is a DOM node, and not the text of a DOM node. + * + * This sanitizer helps prune infeasible paths in type-overloaded functions. + */ + class HasNodePropertySanitizerGuard extends TaintTracking::SanitizerGuardNode { + DataFlow::PropRead read; + + HasNodePropertySanitizerGuard() { + read = this and + read.getPropertyName() = ["nodeType", "jquery"] + } + + override predicate sanitizes(boolean outcome, Expr e) { + e = read.getBase().asExpr() and outcome = true + } + } +} diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom.expected b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom.expected new file mode 100644 index 00000000000..f32705554de --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom.expected @@ -0,0 +1,63 @@ +nodes +| xss-through-dom.js:2:16:2:34 | $("textarea").val() | +| xss-through-dom.js:2:16:2:34 | $("textarea").val() | +| xss-through-dom.js:2:16:2:34 | $("textarea").val() | +| xss-through-dom.js:4:16:4:40 | $(".som ... .text() | +| xss-through-dom.js:4:16:4:40 | $(".som ... .text() | +| xss-through-dom.js:4:16:4:40 | $(".som ... .text() | +| xss-through-dom.js:8:16:8:53 | $(".som ... arget") | +| xss-through-dom.js:8:16:8:53 | $(".som ... arget") | +| xss-through-dom.js:8:16:8:53 | $(".som ... arget") | +| xss-through-dom.js:11:3:11:42 | documen ... nerText | +| xss-through-dom.js:11:3:11:42 | documen ... nerText | +| xss-through-dom.js:11:3:11:42 | documen ... nerText | +| xss-through-dom.js:19:3:19:44 | documen ... Content | +| xss-through-dom.js:19:3:19:44 | documen ... Content | +| xss-through-dom.js:19:3:19:44 | documen ... Content | +| xss-through-dom.js:23:3:23:48 | documen ... ].value | +| xss-through-dom.js:23:3:23:48 | documen ... ].value | +| xss-through-dom.js:23:3:23:48 | documen ... ].value | +| xss-through-dom.js:27:3:27:61 | documen ... arget') | +| xss-through-dom.js:27:3:27:61 | documen ... arget') | +| xss-through-dom.js:27:3:27:61 | documen ... arget') | +| xss-through-dom.js:51:30:51:48 | $("textarea").val() | +| xss-through-dom.js:51:30:51:48 | $("textarea").val() | +| xss-through-dom.js:51:30:51:48 | $("textarea").val() | +| xss-through-dom.js:54:31:54:49 | $("textarea").val() | +| xss-through-dom.js:54:31:54:49 | $("textarea").val() | +| xss-through-dom.js:54:31:54:49 | $("textarea").val() | +| xss-through-dom.js:56:30:56:51 | $("inpu ... 0).name | +| xss-through-dom.js:56:30:56:51 | $("inpu ... 0).name | +| xss-through-dom.js:56:30:56:51 | $("inpu ... 0).name | +| xss-through-dom.js:57:30:57:67 | $("inpu ... "name") | +| xss-through-dom.js:57:30:57:67 | $("inpu ... "name") | +| xss-through-dom.js:57:30:57:67 | $("inpu ... "name") | +| xss-through-dom.js:61:30:61:69 | $(docum ... value") | +| xss-through-dom.js:61:30:61:69 | $(docum ... value") | +| xss-through-dom.js:61:30:61:69 | $(docum ... value") | +edges +| xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | +| xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | +| xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | +| xss-through-dom.js:11:3:11:42 | documen ... nerText | xss-through-dom.js:11:3:11:42 | documen ... nerText | +| xss-through-dom.js:19:3:19:44 | documen ... Content | xss-through-dom.js:19:3:19:44 | documen ... Content | +| xss-through-dom.js:23:3:23:48 | documen ... ].value | xss-through-dom.js:23:3:23:48 | documen ... ].value | +| xss-through-dom.js:27:3:27:61 | documen ... arget') | xss-through-dom.js:27:3:27:61 | documen ... arget') | +| xss-through-dom.js:51:30:51:48 | $("textarea").val() | xss-through-dom.js:51:30:51:48 | $("textarea").val() | +| xss-through-dom.js:54:31:54:49 | $("textarea").val() | xss-through-dom.js:54:31:54:49 | $("textarea").val() | +| xss-through-dom.js:56:30:56:51 | $("inpu ... 0).name | xss-through-dom.js:56:30:56:51 | $("inpu ... 0).name | +| xss-through-dom.js:57:30:57:67 | $("inpu ... "name") | xss-through-dom.js:57:30:57:67 | $("inpu ... "name") | +| xss-through-dom.js:61:30:61:69 | $(docum ... value") | xss-through-dom.js:61:30:61:69 | $(docum ... value") | +#select +| xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:2:16:2:34 | $("textarea").val() | DOM text | +| xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | DOM text | +| xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | DOM text | +| xss-through-dom.js:11:3:11:42 | documen ... nerText | xss-through-dom.js:11:3:11:42 | documen ... nerText | xss-through-dom.js:11:3:11:42 | documen ... nerText | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:11:3:11:42 | documen ... nerText | DOM text | +| xss-through-dom.js:19:3:19:44 | documen ... Content | xss-through-dom.js:19:3:19:44 | documen ... Content | xss-through-dom.js:19:3:19:44 | documen ... Content | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:19:3:19:44 | documen ... Content | DOM text | +| xss-through-dom.js:23:3:23:48 | documen ... ].value | xss-through-dom.js:23:3:23:48 | documen ... ].value | xss-through-dom.js:23:3:23:48 | documen ... ].value | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:23:3:23:48 | documen ... ].value | DOM text | +| xss-through-dom.js:27:3:27:61 | documen ... arget') | xss-through-dom.js:27:3:27:61 | documen ... arget') | xss-through-dom.js:27:3:27:61 | documen ... arget') | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:27:3:27:61 | documen ... arget') | DOM text | +| xss-through-dom.js:51:30:51:48 | $("textarea").val() | xss-through-dom.js:51:30:51:48 | $("textarea").val() | xss-through-dom.js:51:30:51:48 | $("textarea").val() | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:51:30:51:48 | $("textarea").val() | DOM text | +| xss-through-dom.js:54:31:54:49 | $("textarea").val() | xss-through-dom.js:54:31:54:49 | $("textarea").val() | xss-through-dom.js:54:31:54:49 | $("textarea").val() | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:54:31:54:49 | $("textarea").val() | DOM text | +| xss-through-dom.js:56:30:56:51 | $("inpu ... 0).name | xss-through-dom.js:56:30:56:51 | $("inpu ... 0).name | xss-through-dom.js:56:30:56:51 | $("inpu ... 0).name | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:56:30:56:51 | $("inpu ... 0).name | DOM text | +| xss-through-dom.js:57:30:57:67 | $("inpu ... "name") | xss-through-dom.js:57:30:57:67 | $("inpu ... "name") | xss-through-dom.js:57:30:57:67 | $("inpu ... "name") | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:57:30:57:67 | $("inpu ... "name") | DOM text | +| xss-through-dom.js:61:30:61:69 | $(docum ... value") | xss-through-dom.js:61:30:61:69 | $(docum ... value") | xss-through-dom.js:61:30:61:69 | $(docum ... value") | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:61:30:61:69 | $(docum ... value") | DOM text | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom.qlref b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom.qlref new file mode 100644 index 00000000000..3226decda37 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom.qlref @@ -0,0 +1 @@ +Security/CWE-079/XssThroughDom.ql diff --git a/javascript/ql/test/query-tests/Security/CWE-079/xss-through-dom.js b/javascript/ql/test/query-tests/Security/CWE-079/xss-through-dom.js new file mode 100644 index 00000000000..98947e96ff3 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-079/xss-through-dom.js @@ -0,0 +1,62 @@ +(function () { + $("#id").html($("textarea").val()); // NOT OK. + + $("#id").html($(".some-element").text()); // NOT OK. + + $("#id").html($(".some-element").attr("foo", "bar")); // OK. + $("#id").html($(".some-element").attr({"foo": "bar"})); // OK. + $("#id").html($(".some-element").attr("data-target")); // NOT OK. + + $("#id").html( + document.getElementById("foo").innerText // NOT OK. + ); + + $("#id").html( + document.getElementById("foo").innerHTML // OK - only repeats existing XSS. + ); + + $("#id").html( + document.getElementById("foo").textContent // NOT OK. + ); + + $("#id").html( + document.querySelectorAll("textarea")[0].value // NOT OK. + ); + + $("#id").html( + document.getElementById('div1').getAttribute('data-target') // NOT OK + ); + + function safe1(x) { // overloaded function. + if (x.jquery) { + var foo = $(x); // OK + } + + } + safe1($("textarea").val()); + + function safe2(x) { // overloaded function. + if (typeof x === "object") { + var foo = $(x); // OK + } + } + safe2($("textarea").val()); + + + $("#id").html( + $("

    " + something() + "

    ").text() // OK - this is for a flow-step to catch, not this query. + ); + + + $("#id").get(0).innerHTML = $("textarea").val(); // NOT OK. + + var base = $("#id"); + base[html ? 'html' : 'text']($("textarea").val()); // NOT OK. + + $("#id").get(0).innerHTML = $("input").get(0).name; // NOT OK. + $("#id").get(0).innerHTML = $("input").get(0).getAttribute("name"); // NOT OK. + + $("#id").get(0).innerHTML = $("input").getAttribute("id"); // OK. + + $("#id").get(0).innerHTML = $(document).find("option").attr("value"); // NOT OK. +})(); \ No newline at end of file From 1b80f46f30477c52c90e6c4697f92594f865d362 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 3 Apr 2020 15:54:27 +0200 Subject: [PATCH 0168/1298] add QHelp for js/xss-through-dom query --- .../src/Security/CWE-079/XssThroughDom.qhelp | 71 +++++++++++++++++++ .../CWE-079/examples/XssThroughDom.js | 4 ++ .../CWE-079/examples/XssThroughDomFixed.js | 4 ++ 3 files changed, 79 insertions(+) create mode 100644 javascript/ql/src/Security/CWE-079/XssThroughDom.qhelp create mode 100644 javascript/ql/src/Security/CWE-079/examples/XssThroughDom.js create mode 100644 javascript/ql/src/Security/CWE-079/examples/XssThroughDomFixed.js diff --git a/javascript/ql/src/Security/CWE-079/XssThroughDom.qhelp b/javascript/ql/src/Security/CWE-079/XssThroughDom.qhelp new file mode 100644 index 00000000000..297e3739fee --- /dev/null +++ b/javascript/ql/src/Security/CWE-079/XssThroughDom.qhelp @@ -0,0 +1,71 @@ + + + + +

    +Writing text from a webpage to the same webpage without properly sanitizing the +input first, might allow for a cross-site scripting vulnerability. +

    +

    +A webpage with this vulnerability unescapes an otherwise sanitized text, +and thereby allows an attacker to use sanitized text in the DOM to perform a +cross-site scripting attack. +

    +
    + + +

    +To guard against cross-site scripting, consider using contextual output encoding/escaping before +writing text to the page, or one of the other solutions that are mentioned in the references. +

    +
    + + +

    +The following example shows a webpage using a data-target attribute +to select and manipulate a DOM element using the JQuery library. In the example, the +data-target attribute is read into the target variable, and the +$ function is then supposed to use the target variable as a CSS +selector to determine which element should be manipulated. +

    + +

    +However, if an attacker can control the data-target attribute, +then the value of target can be used to cause the $ function +to execute arbitary JavaScript. +

    +

    +The above vulnerability can be fixed by using $.find instead of $. +The $.find function will only interpret target as a CSS selector +and never as HTML, thereby preventing an XSS attack. +

    + +
    + + +
  • +OWASP: +DOM based +XSS Prevention Cheat Sheet. +
  • +
  • +OWASP: +XSS +(Cross Site Scripting) Prevention Cheat Sheet. +
  • +
  • +OWASP +DOM Based XSS. +
  • +
  • +OWASP +Types of Cross-Site +Scripting. +
  • +
  • +Wikipedia: Cross-site scripting. +
  • + + diff --git a/javascript/ql/src/Security/CWE-079/examples/XssThroughDom.js b/javascript/ql/src/Security/CWE-079/examples/XssThroughDom.js new file mode 100644 index 00000000000..cfbc3c08069 --- /dev/null +++ b/javascript/ql/src/Security/CWE-079/examples/XssThroughDom.js @@ -0,0 +1,4 @@ +$("button").click(function () { + var target = this.attr("data-target"); + $(target).hide(); +}); diff --git a/javascript/ql/src/Security/CWE-079/examples/XssThroughDomFixed.js b/javascript/ql/src/Security/CWE-079/examples/XssThroughDomFixed.js new file mode 100644 index 00000000000..3bc9e36267d --- /dev/null +++ b/javascript/ql/src/Security/CWE-079/examples/XssThroughDomFixed.js @@ -0,0 +1,4 @@ +$("button").click(function () { + var target = this.attr("data-target"); + $.find(target).hide(); +}); From c36142f129e075dde82c4d82cc8a68d95f546ee9 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 16 Apr 2020 11:52:30 +0200 Subject: [PATCH 0169/1298] C#: Add data-flow test for collections --- .../dataflow/arrays/ArrayFlow.cs | 229 +++++++++++++++++ .../dataflow/arrays/ArrayFlow.expected | 235 ++++++++++++++++++ .../dataflow/arrays/ArrayFlow.ql | 23 ++ 3 files changed, 487 insertions(+) create mode 100644 csharp/ql/test/library-tests/dataflow/arrays/ArrayFlow.cs create mode 100644 csharp/ql/test/library-tests/dataflow/arrays/ArrayFlow.expected create mode 100644 csharp/ql/test/library-tests/dataflow/arrays/ArrayFlow.ql diff --git a/csharp/ql/test/library-tests/dataflow/arrays/ArrayFlow.cs b/csharp/ql/test/library-tests/dataflow/arrays/ArrayFlow.cs new file mode 100644 index 00000000000..37ae6c6d299 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/arrays/ArrayFlow.cs @@ -0,0 +1,229 @@ +// semmle-extractor-options: /r:System.Linq.dll +using System; +using System.Collections.Generic; +using System.Linq; + +public class A +{ + public void M1() + { + var a = new A(); + var @as = new[] { a }; + Sink(@as[0]); // flow + SinkElem(@as); // flow + Sink(First(@as)); // flow + } + + public void M2(A other) + { + var a = new A(); + var @as = new[] { other }; + Sink(@as[0]); // no flow + SinkElem(@as); // no flow + Sink(First(@as)); // no flow + } + + public void M3() + { + var a = new A(); + var @as = new A[1]; + @as[0] = a; + Sink(@as[0]); // flow + SinkElem(@as); // flow + Sink(First(@as)); // flow + } + + public void M4(A other) + { + var a = new A(); + var @as = new A[1]; + @as[0] = other; + Sink(@as[0]); // no flow + SinkElem(@as); // no flow + Sink(First(@as)); // no flow + } + + public void M5() + { + var a = new A(); + var list = new List(); + list[0] = a; + Sink(list[0]); // flow + SinkListElem(list); // flow + Sink(ListFirst(list)); // flow + } + + public void M6(A other) + { + var list = new List(); + list[0] = other; + Sink(list[0]); // no flow + SinkListElem(list); // no flow + Sink(ListFirst(list)); // no flow + } + + public void M7() + { + var a = new A(); + var list = new List() { a }; + Sink(list[0]); // flow + SinkListElem(list); // flow + Sink(ListFirst(list)); // flow + } + + public void M8(A other) + { + var list = new List() { other }; + Sink(list[0]); // no flow + SinkListElem(list); // no flow + Sink(ListFirst(list)); // no flow + } + + public void M9() + { + var a = new A(); + var list = new List(); + list.Add(a); + Sink(list[0]); // flow + SinkListElem(list); // flow + Sink(ListFirst(list)); // flow + } + + public void M10(A other) + { + var list = new List(); + list.Add(other); + Sink(list[0]); // no flow + SinkListElem(list); // no flow + Sink(ListFirst(list)); // no flow + } + + public void M11() + { + var a = new A(); + var dict = new Dictionary(); + dict[0] = a; + Sink(dict[0]); // flow + SinkDictValue(dict); // flow + Sink(DictFirstValueA(dict)); // flow + Sink(DictFirstValueB(dict)); // flow [MISSING] + Sink(DictFirstValueC(dict)); // flow + } + + public void M12(A other) + { + var dict = new Dictionary(); + dict[0] = other; + Sink(dict[0]); // no flow + SinkDictValue(dict); // no flow + Sink(DictFirstValueA(dict)); // no flow + Sink(DictFirstValueB(dict)); // no flow + Sink(DictFirstValueC(dict)); // no flow + } + + public void M13() + { + var a = new A(); + var dict = new Dictionary() { { 0, a } }; + Sink(dict[0]); // flow + SinkDictValue(dict); // flow + Sink(DictFirstValueA(dict)); // flow + Sink(DictFirstValueB(dict)); // flow [MISSING] + Sink(DictFirstValueC(dict)); // flow + } + + public void M14(A other) + { + var dict = new Dictionary() { { 0, other } }; + Sink(dict[0]); // no flow + SinkDictValue(dict); // no flow + Sink(DictFirstValueA(dict)); // no flow + Sink(DictFirstValueB(dict)); // no flow + Sink(DictFirstValueC(dict)); // no flow + } + + public void M15() + { + var a = new A(); + var dict = new Dictionary() { { a, 0 } }; + Sink(dict.Keys.First()); // flow [MISSING] + SinkDictKey(dict); // flow [MISSING] + Sink(DictFirstKeyA(dict)); // flow [MISSING] + Sink(DictFirstKeyB(dict)); // flow [MISSING] + } + + public void M16(A other) + { + var dict = new Dictionary() { { other, 0 } }; + Sink(dict.Keys.First()); // no flow + SinkDictKey(dict); // no flow + Sink(DictFirstKeyA(dict)); // no flow + Sink(DictFirstKeyB(dict)); // no flow + } + + public void M17() + { + var a = new A(); + var @as = new[] { a }; + foreach (var x in @as) + Sink(x); // flow + } + + public void M18(A other) + { + var @as = new[] { other }; + foreach (var x in @as) + Sink(x); // no flow + } + + public void M19() + { + var a = new A(); + var @as = new[] { a }; + var enumerator = @as.GetEnumerator(); + while (enumerator.MoveNext()) + Sink(enumerator.Current); // flow + } + + public void M20(A other) + { + var @as = new[] { other }; + var enumerator = @as.GetEnumerator(); + while (enumerator.MoveNext()) + Sink(enumerator.Current); // no flow + } + + public void M21() + { + var a = new A(); + var list = new List(); + list.Add(a); + var enumerator = list.GetEnumerator(); + while (enumerator.MoveNext()) + Sink(enumerator.Current); // flow [MISSING] + } + + public static void Sink(T t) { } + + public static void SinkElem(T[] ts) => Sink(ts[0]); + + public static void SinkListElem(IList list) => Sink(list[0]); + + public static void SinkDictValue(IDictionary dict) => Sink(dict[0]); + + public static void SinkDictKey(IDictionary dict) => Sink(dict.Keys.First()); + + public static T First(T[] ts) => ts[0]; + + public static T ListFirst(IList list) => list[0]; + + public static T DictFirstValueA(IDictionary dict) => dict[0]; + + public static T DictFirstValueB(IDictionary dict) => dict.First().Value; + + public static T DictFirstValueC(IDictionary dict) => dict.Values.First(); + + public static T DictFirstKeyA(IDictionary dict) => dict.Keys.First(); + + public static T DictFirstKeyB(IDictionary dict) => dict.First().Key; +} diff --git a/csharp/ql/test/library-tests/dataflow/arrays/ArrayFlow.expected b/csharp/ql/test/library-tests/dataflow/arrays/ArrayFlow.expected new file mode 100644 index 00000000000..9a0b41ef207 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/arrays/ArrayFlow.expected @@ -0,0 +1,235 @@ +edges +| ArrayFlow.cs:10:17:10:23 | object creation of type A : A | ArrayFlow.cs:12:14:12:19 | access to array element | +| ArrayFlow.cs:10:17:10:23 | object creation of type A : A | ArrayFlow.cs:13:18:13:20 | access to local variable as : A[] | +| ArrayFlow.cs:10:17:10:23 | object creation of type A : A | ArrayFlow.cs:14:20:14:22 | access to local variable as : A[] | +| ArrayFlow.cs:13:18:13:20 | access to local variable as : A[] | ArrayFlow.cs:208:40:208:41 | ts : A[] | +| ArrayFlow.cs:14:20:14:22 | access to local variable as : A[] | ArrayFlow.cs:14:14:14:23 | call to method First | +| ArrayFlow.cs:28:17:28:23 | object creation of type A : A | ArrayFlow.cs:31:14:31:19 | access to array element | +| ArrayFlow.cs:28:17:28:23 | object creation of type A : A | ArrayFlow.cs:32:18:32:20 | access to local variable as : A[] | +| ArrayFlow.cs:28:17:28:23 | object creation of type A : A | ArrayFlow.cs:33:20:33:22 | access to local variable as : A[] | +| ArrayFlow.cs:32:18:32:20 | access to local variable as : A[] | ArrayFlow.cs:208:40:208:41 | ts : A[] | +| ArrayFlow.cs:33:20:33:22 | access to local variable as : A[] | ArrayFlow.cs:33:14:33:23 | call to method First | +| ArrayFlow.cs:48:17:48:23 | object creation of type A : A | ArrayFlow.cs:51:14:51:20 | access to indexer | +| ArrayFlow.cs:48:17:48:23 | object creation of type A : A | ArrayFlow.cs:52:22:52:25 | access to local variable list : List | +| ArrayFlow.cs:48:17:48:23 | object creation of type A : A | ArrayFlow.cs:53:24:53:27 | access to local variable list : List | +| ArrayFlow.cs:49:20:49:32 | object creation of type List : List | ArrayFlow.cs:51:14:51:20 | access to indexer | +| ArrayFlow.cs:49:20:49:32 | object creation of type List : List | ArrayFlow.cs:52:22:52:25 | access to local variable list : List | +| ArrayFlow.cs:49:20:49:32 | object creation of type List : List | ArrayFlow.cs:53:24:53:27 | access to local variable list : List | +| ArrayFlow.cs:52:22:52:25 | access to local variable list : List | ArrayFlow.cs:210:49:210:52 | list : List | +| ArrayFlow.cs:53:24:53:27 | access to local variable list : List | ArrayFlow.cs:53:14:53:28 | call to method ListFirst | +| ArrayFlow.cs:58:20:58:32 | object creation of type List : List | ArrayFlow.cs:60:14:60:20 | access to indexer | +| ArrayFlow.cs:58:20:58:32 | object creation of type List : List | ArrayFlow.cs:61:22:61:25 | access to local variable list : List | +| ArrayFlow.cs:58:20:58:32 | object creation of type List : List | ArrayFlow.cs:62:24:62:27 | access to local variable list : List | +| ArrayFlow.cs:61:22:61:25 | access to local variable list : List | ArrayFlow.cs:210:49:210:52 | list : List | +| ArrayFlow.cs:62:24:62:27 | access to local variable list : List | ArrayFlow.cs:62:14:62:28 | call to method ListFirst | +| ArrayFlow.cs:67:17:67:23 | object creation of type A : A | ArrayFlow.cs:69:14:69:20 | access to indexer | +| ArrayFlow.cs:67:17:67:23 | object creation of type A : A | ArrayFlow.cs:70:22:70:25 | access to local variable list : List | +| ArrayFlow.cs:67:17:67:23 | object creation of type A : A | ArrayFlow.cs:71:24:71:27 | access to local variable list : List | +| ArrayFlow.cs:68:20:68:38 | object creation of type List : List | ArrayFlow.cs:69:14:69:20 | access to indexer | +| ArrayFlow.cs:68:20:68:38 | object creation of type List : List | ArrayFlow.cs:70:22:70:25 | access to local variable list : List | +| ArrayFlow.cs:68:20:68:38 | object creation of type List : List | ArrayFlow.cs:71:24:71:27 | access to local variable list : List | +| ArrayFlow.cs:70:22:70:25 | access to local variable list : List | ArrayFlow.cs:210:49:210:52 | list : List | +| ArrayFlow.cs:71:24:71:27 | access to local variable list : List | ArrayFlow.cs:71:14:71:28 | call to method ListFirst | +| ArrayFlow.cs:76:20:76:42 | object creation of type List : List | ArrayFlow.cs:77:14:77:20 | access to indexer | +| ArrayFlow.cs:76:20:76:42 | object creation of type List : List | ArrayFlow.cs:78:22:78:25 | access to local variable list : List | +| ArrayFlow.cs:76:20:76:42 | object creation of type List : List | ArrayFlow.cs:79:24:79:27 | access to local variable list : List | +| ArrayFlow.cs:78:22:78:25 | access to local variable list : List | ArrayFlow.cs:210:49:210:52 | list : List | +| ArrayFlow.cs:79:24:79:27 | access to local variable list : List | ArrayFlow.cs:79:14:79:28 | call to method ListFirst | +| ArrayFlow.cs:84:17:84:23 | object creation of type A : A | ArrayFlow.cs:87:14:87:20 | access to indexer | +| ArrayFlow.cs:84:17:84:23 | object creation of type A : A | ArrayFlow.cs:88:22:88:25 | access to local variable list : List | +| ArrayFlow.cs:84:17:84:23 | object creation of type A : A | ArrayFlow.cs:89:24:89:27 | access to local variable list : List | +| ArrayFlow.cs:85:20:85:32 | object creation of type List : List | ArrayFlow.cs:87:14:87:20 | access to indexer | +| ArrayFlow.cs:85:20:85:32 | object creation of type List : List | ArrayFlow.cs:88:22:88:25 | access to local variable list : List | +| ArrayFlow.cs:85:20:85:32 | object creation of type List : List | ArrayFlow.cs:89:24:89:27 | access to local variable list : List | +| ArrayFlow.cs:88:22:88:25 | access to local variable list : List | ArrayFlow.cs:210:49:210:52 | list : List | +| ArrayFlow.cs:89:24:89:27 | access to local variable list : List | ArrayFlow.cs:89:14:89:28 | call to method ListFirst | +| ArrayFlow.cs:94:20:94:32 | object creation of type List : List | ArrayFlow.cs:96:14:96:20 | access to indexer | +| ArrayFlow.cs:94:20:94:32 | object creation of type List : List | ArrayFlow.cs:97:22:97:25 | access to local variable list : List | +| ArrayFlow.cs:94:20:94:32 | object creation of type List : List | ArrayFlow.cs:98:24:98:27 | access to local variable list : List | +| ArrayFlow.cs:97:22:97:25 | access to local variable list : List | ArrayFlow.cs:210:49:210:52 | list : List | +| ArrayFlow.cs:98:24:98:27 | access to local variable list : List | ArrayFlow.cs:98:14:98:28 | call to method ListFirst | +| ArrayFlow.cs:103:17:103:23 | object creation of type A : A | ArrayFlow.cs:106:14:106:20 | access to indexer | +| ArrayFlow.cs:103:17:103:23 | object creation of type A : A | ArrayFlow.cs:107:23:107:26 | access to local variable dict : Dictionary | +| ArrayFlow.cs:103:17:103:23 | object creation of type A : A | ArrayFlow.cs:108:30:108:33 | access to local variable dict : Dictionary | +| ArrayFlow.cs:103:17:103:23 | object creation of type A : A | ArrayFlow.cs:110:30:110:33 | access to local variable dict : Dictionary | +| ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:106:14:106:20 | access to indexer | +| ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:107:23:107:26 | access to local variable dict : Dictionary | +| ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:108:30:108:33 | access to local variable dict : Dictionary | +| ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:110:30:110:33 | access to local variable dict : Dictionary | +| ArrayFlow.cs:107:23:107:26 | access to local variable dict : Dictionary | ArrayFlow.cs:212:61:212:64 | dict : Dictionary | +| ArrayFlow.cs:108:30:108:33 | access to local variable dict : Dictionary | ArrayFlow.cs:108:14:108:34 | call to method DictFirstValueA | +| ArrayFlow.cs:110:30:110:33 | access to local variable dict : Dictionary | ArrayFlow.cs:110:14:110:34 | call to method DictFirstValueC | +| ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:117:14:117:20 | access to indexer | +| ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:118:23:118:26 | access to local variable dict : Dictionary | +| ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:119:30:119:33 | access to local variable dict : Dictionary | +| ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:121:30:121:33 | access to local variable dict : Dictionary | +| ArrayFlow.cs:118:23:118:26 | access to local variable dict : Dictionary | ArrayFlow.cs:212:61:212:64 | dict : Dictionary | +| ArrayFlow.cs:119:30:119:33 | access to local variable dict : Dictionary | ArrayFlow.cs:119:14:119:34 | call to method DictFirstValueA | +| ArrayFlow.cs:121:30:121:33 | access to local variable dict : Dictionary | ArrayFlow.cs:121:14:121:34 | call to method DictFirstValueC | +| ArrayFlow.cs:126:17:126:23 | object creation of type A : A | ArrayFlow.cs:128:14:128:20 | access to indexer | +| ArrayFlow.cs:126:17:126:23 | object creation of type A : A | ArrayFlow.cs:129:23:129:26 | access to local variable dict : Dictionary | +| ArrayFlow.cs:126:17:126:23 | object creation of type A : A | ArrayFlow.cs:130:30:130:33 | access to local variable dict : Dictionary | +| ArrayFlow.cs:126:17:126:23 | object creation of type A : A | ArrayFlow.cs:132:30:132:33 | access to local variable dict : Dictionary | +| ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:128:14:128:20 | access to indexer | +| ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:129:23:129:26 | access to local variable dict : Dictionary | +| ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:130:30:130:33 | access to local variable dict : Dictionary | +| ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:132:30:132:33 | access to local variable dict : Dictionary | +| ArrayFlow.cs:129:23:129:26 | access to local variable dict : Dictionary | ArrayFlow.cs:212:61:212:64 | dict : Dictionary | +| ArrayFlow.cs:130:30:130:33 | access to local variable dict : Dictionary | ArrayFlow.cs:130:14:130:34 | call to method DictFirstValueA | +| ArrayFlow.cs:132:30:132:33 | access to local variable dict : Dictionary | ArrayFlow.cs:132:14:132:34 | call to method DictFirstValueC | +| ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:138:14:138:20 | access to indexer | +| ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:139:23:139:26 | access to local variable dict : Dictionary | +| ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:140:30:140:33 | access to local variable dict : Dictionary | +| ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:142:30:142:33 | access to local variable dict : Dictionary | +| ArrayFlow.cs:139:23:139:26 | access to local variable dict : Dictionary | ArrayFlow.cs:212:61:212:64 | dict : Dictionary | +| ArrayFlow.cs:140:30:140:33 | access to local variable dict : Dictionary | ArrayFlow.cs:140:14:140:34 | call to method DictFirstValueA | +| ArrayFlow.cs:142:30:142:33 | access to local variable dict : Dictionary | ArrayFlow.cs:142:14:142:34 | call to method DictFirstValueC | +| ArrayFlow.cs:166:17:166:23 | object creation of type A : A | ArrayFlow.cs:169:18:169:18 | access to local variable x | +| ArrayFlow.cs:181:17:181:23 | object creation of type A : A | ArrayFlow.cs:185:18:185:35 | access to property Current | +| ArrayFlow.cs:208:40:208:41 | ts : A[] | ArrayFlow.cs:208:52:208:56 | access to array element | +| ArrayFlow.cs:210:49:210:52 | list : List | ArrayFlow.cs:210:63:210:69 | access to indexer | +| ArrayFlow.cs:212:61:212:64 | dict : Dictionary | ArrayFlow.cs:212:75:212:81 | access to indexer | +nodes +| ArrayFlow.cs:10:17:10:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| ArrayFlow.cs:12:14:12:19 | access to array element | semmle.label | access to array element | +| ArrayFlow.cs:13:18:13:20 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | +| ArrayFlow.cs:14:14:14:23 | call to method First | semmle.label | call to method First | +| ArrayFlow.cs:14:20:14:22 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | +| ArrayFlow.cs:28:17:28:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| ArrayFlow.cs:31:14:31:19 | access to array element | semmle.label | access to array element | +| ArrayFlow.cs:32:18:32:20 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | +| ArrayFlow.cs:33:14:33:23 | call to method First | semmle.label | call to method First | +| ArrayFlow.cs:33:20:33:22 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | +| ArrayFlow.cs:48:17:48:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| ArrayFlow.cs:49:20:49:32 | object creation of type List : List | semmle.label | object creation of type List : List | +| ArrayFlow.cs:51:14:51:20 | access to indexer | semmle.label | access to indexer | +| ArrayFlow.cs:52:22:52:25 | access to local variable list : List | semmle.label | access to local variable list : List | +| ArrayFlow.cs:53:14:53:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| ArrayFlow.cs:53:24:53:27 | access to local variable list : List | semmle.label | access to local variable list : List | +| ArrayFlow.cs:58:20:58:32 | object creation of type List : List | semmle.label | object creation of type List : List | +| ArrayFlow.cs:60:14:60:20 | access to indexer | semmle.label | access to indexer | +| ArrayFlow.cs:61:22:61:25 | access to local variable list : List | semmle.label | access to local variable list : List | +| ArrayFlow.cs:62:14:62:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| ArrayFlow.cs:62:24:62:27 | access to local variable list : List | semmle.label | access to local variable list : List | +| ArrayFlow.cs:67:17:67:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| ArrayFlow.cs:68:20:68:38 | object creation of type List : List | semmle.label | object creation of type List : List | +| ArrayFlow.cs:69:14:69:20 | access to indexer | semmle.label | access to indexer | +| ArrayFlow.cs:70:22:70:25 | access to local variable list : List | semmle.label | access to local variable list : List | +| ArrayFlow.cs:71:14:71:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| ArrayFlow.cs:71:24:71:27 | access to local variable list : List | semmle.label | access to local variable list : List | +| ArrayFlow.cs:76:20:76:42 | object creation of type List : List | semmle.label | object creation of type List : List | +| ArrayFlow.cs:77:14:77:20 | access to indexer | semmle.label | access to indexer | +| ArrayFlow.cs:78:22:78:25 | access to local variable list : List | semmle.label | access to local variable list : List | +| ArrayFlow.cs:79:14:79:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| ArrayFlow.cs:79:24:79:27 | access to local variable list : List | semmle.label | access to local variable list : List | +| ArrayFlow.cs:84:17:84:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| ArrayFlow.cs:85:20:85:32 | object creation of type List : List | semmle.label | object creation of type List : List | +| ArrayFlow.cs:87:14:87:20 | access to indexer | semmle.label | access to indexer | +| ArrayFlow.cs:88:22:88:25 | access to local variable list : List | semmle.label | access to local variable list : List | +| ArrayFlow.cs:89:14:89:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| ArrayFlow.cs:89:24:89:27 | access to local variable list : List | semmle.label | access to local variable list : List | +| ArrayFlow.cs:94:20:94:32 | object creation of type List : List | semmle.label | object creation of type List : List | +| ArrayFlow.cs:96:14:96:20 | access to indexer | semmle.label | access to indexer | +| ArrayFlow.cs:97:22:97:25 | access to local variable list : List | semmle.label | access to local variable list : List | +| ArrayFlow.cs:98:14:98:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| ArrayFlow.cs:98:24:98:27 | access to local variable list : List | semmle.label | access to local variable list : List | +| ArrayFlow.cs:103:17:103:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | +| ArrayFlow.cs:106:14:106:20 | access to indexer | semmle.label | access to indexer | +| ArrayFlow.cs:107:23:107:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| ArrayFlow.cs:108:14:108:34 | call to method DictFirstValueA | semmle.label | call to method DictFirstValueA | +| ArrayFlow.cs:108:30:108:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| ArrayFlow.cs:110:14:110:34 | call to method DictFirstValueC | semmle.label | call to method DictFirstValueC | +| ArrayFlow.cs:110:30:110:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | +| ArrayFlow.cs:117:14:117:20 | access to indexer | semmle.label | access to indexer | +| ArrayFlow.cs:118:23:118:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| ArrayFlow.cs:119:14:119:34 | call to method DictFirstValueA | semmle.label | call to method DictFirstValueA | +| ArrayFlow.cs:119:30:119:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| ArrayFlow.cs:121:14:121:34 | call to method DictFirstValueC | semmle.label | call to method DictFirstValueC | +| ArrayFlow.cs:121:30:121:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| ArrayFlow.cs:126:17:126:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | +| ArrayFlow.cs:128:14:128:20 | access to indexer | semmle.label | access to indexer | +| ArrayFlow.cs:129:23:129:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| ArrayFlow.cs:130:14:130:34 | call to method DictFirstValueA | semmle.label | call to method DictFirstValueA | +| ArrayFlow.cs:130:30:130:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| ArrayFlow.cs:132:14:132:34 | call to method DictFirstValueC | semmle.label | call to method DictFirstValueC | +| ArrayFlow.cs:132:30:132:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | +| ArrayFlow.cs:138:14:138:20 | access to indexer | semmle.label | access to indexer | +| ArrayFlow.cs:139:23:139:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| ArrayFlow.cs:140:14:140:34 | call to method DictFirstValueA | semmle.label | call to method DictFirstValueA | +| ArrayFlow.cs:140:30:140:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| ArrayFlow.cs:142:14:142:34 | call to method DictFirstValueC | semmle.label | call to method DictFirstValueC | +| ArrayFlow.cs:142:30:142:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| ArrayFlow.cs:166:17:166:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| ArrayFlow.cs:169:18:169:18 | access to local variable x | semmle.label | access to local variable x | +| ArrayFlow.cs:181:17:181:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| ArrayFlow.cs:185:18:185:35 | access to property Current | semmle.label | access to property Current | +| ArrayFlow.cs:208:40:208:41 | ts : A[] | semmle.label | ts : A[] | +| ArrayFlow.cs:208:52:208:56 | access to array element | semmle.label | access to array element | +| ArrayFlow.cs:210:49:210:52 | list : List | semmle.label | list : List | +| ArrayFlow.cs:210:63:210:69 | access to indexer | semmle.label | access to indexer | +| ArrayFlow.cs:212:61:212:64 | dict : Dictionary | semmle.label | dict : Dictionary | +| ArrayFlow.cs:212:75:212:81 | access to indexer | semmle.label | access to indexer | +#select +| ArrayFlow.cs:10:17:10:23 | object creation of type A : A | ArrayFlow.cs:10:17:10:23 | object creation of type A : A | ArrayFlow.cs:12:14:12:19 | access to array element | $@ | ArrayFlow.cs:12:14:12:19 | access to array element | access to array element | +| ArrayFlow.cs:10:17:10:23 | object creation of type A : A | ArrayFlow.cs:10:17:10:23 | object creation of type A : A | ArrayFlow.cs:14:14:14:23 | call to method First | $@ | ArrayFlow.cs:14:14:14:23 | call to method First | call to method First | +| ArrayFlow.cs:10:17:10:23 | object creation of type A : A | ArrayFlow.cs:10:17:10:23 | object creation of type A : A | ArrayFlow.cs:208:52:208:56 | access to array element | $@ | ArrayFlow.cs:208:52:208:56 | access to array element | access to array element | +| ArrayFlow.cs:28:17:28:23 | object creation of type A : A | ArrayFlow.cs:28:17:28:23 | object creation of type A : A | ArrayFlow.cs:31:14:31:19 | access to array element | $@ | ArrayFlow.cs:31:14:31:19 | access to array element | access to array element | +| ArrayFlow.cs:28:17:28:23 | object creation of type A : A | ArrayFlow.cs:28:17:28:23 | object creation of type A : A | ArrayFlow.cs:33:14:33:23 | call to method First | $@ | ArrayFlow.cs:33:14:33:23 | call to method First | call to method First | +| ArrayFlow.cs:28:17:28:23 | object creation of type A : A | ArrayFlow.cs:28:17:28:23 | object creation of type A : A | ArrayFlow.cs:208:52:208:56 | access to array element | $@ | ArrayFlow.cs:208:52:208:56 | access to array element | access to array element | +| ArrayFlow.cs:48:17:48:23 | object creation of type A : A | ArrayFlow.cs:48:17:48:23 | object creation of type A : A | ArrayFlow.cs:51:14:51:20 | access to indexer | $@ | ArrayFlow.cs:51:14:51:20 | access to indexer | access to indexer | +| ArrayFlow.cs:48:17:48:23 | object creation of type A : A | ArrayFlow.cs:48:17:48:23 | object creation of type A : A | ArrayFlow.cs:53:14:53:28 | call to method ListFirst | $@ | ArrayFlow.cs:53:14:53:28 | call to method ListFirst | call to method ListFirst | +| ArrayFlow.cs:48:17:48:23 | object creation of type A : A | ArrayFlow.cs:48:17:48:23 | object creation of type A : A | ArrayFlow.cs:210:63:210:69 | access to indexer | $@ | ArrayFlow.cs:210:63:210:69 | access to indexer | access to indexer | +| ArrayFlow.cs:49:20:49:32 | object creation of type List : List | ArrayFlow.cs:49:20:49:32 | object creation of type List : List | ArrayFlow.cs:51:14:51:20 | access to indexer | $@ | ArrayFlow.cs:51:14:51:20 | access to indexer | access to indexer | +| ArrayFlow.cs:49:20:49:32 | object creation of type List : List | ArrayFlow.cs:49:20:49:32 | object creation of type List : List | ArrayFlow.cs:53:14:53:28 | call to method ListFirst | $@ | ArrayFlow.cs:53:14:53:28 | call to method ListFirst | call to method ListFirst | +| ArrayFlow.cs:49:20:49:32 | object creation of type List : List | ArrayFlow.cs:49:20:49:32 | object creation of type List : List | ArrayFlow.cs:210:63:210:69 | access to indexer | $@ | ArrayFlow.cs:210:63:210:69 | access to indexer | access to indexer | +| ArrayFlow.cs:58:20:58:32 | object creation of type List : List | ArrayFlow.cs:58:20:58:32 | object creation of type List : List | ArrayFlow.cs:60:14:60:20 | access to indexer | $@ | ArrayFlow.cs:60:14:60:20 | access to indexer | access to indexer | +| ArrayFlow.cs:58:20:58:32 | object creation of type List : List | ArrayFlow.cs:58:20:58:32 | object creation of type List : List | ArrayFlow.cs:62:14:62:28 | call to method ListFirst | $@ | ArrayFlow.cs:62:14:62:28 | call to method ListFirst | call to method ListFirst | +| ArrayFlow.cs:58:20:58:32 | object creation of type List : List | ArrayFlow.cs:58:20:58:32 | object creation of type List : List | ArrayFlow.cs:210:63:210:69 | access to indexer | $@ | ArrayFlow.cs:210:63:210:69 | access to indexer | access to indexer | +| ArrayFlow.cs:67:17:67:23 | object creation of type A : A | ArrayFlow.cs:67:17:67:23 | object creation of type A : A | ArrayFlow.cs:69:14:69:20 | access to indexer | $@ | ArrayFlow.cs:69:14:69:20 | access to indexer | access to indexer | +| ArrayFlow.cs:67:17:67:23 | object creation of type A : A | ArrayFlow.cs:67:17:67:23 | object creation of type A : A | ArrayFlow.cs:71:14:71:28 | call to method ListFirst | $@ | ArrayFlow.cs:71:14:71:28 | call to method ListFirst | call to method ListFirst | +| ArrayFlow.cs:67:17:67:23 | object creation of type A : A | ArrayFlow.cs:67:17:67:23 | object creation of type A : A | ArrayFlow.cs:210:63:210:69 | access to indexer | $@ | ArrayFlow.cs:210:63:210:69 | access to indexer | access to indexer | +| ArrayFlow.cs:68:20:68:38 | object creation of type List : List | ArrayFlow.cs:68:20:68:38 | object creation of type List : List | ArrayFlow.cs:69:14:69:20 | access to indexer | $@ | ArrayFlow.cs:69:14:69:20 | access to indexer | access to indexer | +| ArrayFlow.cs:68:20:68:38 | object creation of type List : List | ArrayFlow.cs:68:20:68:38 | object creation of type List : List | ArrayFlow.cs:71:14:71:28 | call to method ListFirst | $@ | ArrayFlow.cs:71:14:71:28 | call to method ListFirst | call to method ListFirst | +| ArrayFlow.cs:68:20:68:38 | object creation of type List : List | ArrayFlow.cs:68:20:68:38 | object creation of type List : List | ArrayFlow.cs:210:63:210:69 | access to indexer | $@ | ArrayFlow.cs:210:63:210:69 | access to indexer | access to indexer | +| ArrayFlow.cs:76:20:76:42 | object creation of type List : List | ArrayFlow.cs:76:20:76:42 | object creation of type List : List | ArrayFlow.cs:77:14:77:20 | access to indexer | $@ | ArrayFlow.cs:77:14:77:20 | access to indexer | access to indexer | +| ArrayFlow.cs:76:20:76:42 | object creation of type List : List | ArrayFlow.cs:76:20:76:42 | object creation of type List : List | ArrayFlow.cs:79:14:79:28 | call to method ListFirst | $@ | ArrayFlow.cs:79:14:79:28 | call to method ListFirst | call to method ListFirst | +| ArrayFlow.cs:76:20:76:42 | object creation of type List : List | ArrayFlow.cs:76:20:76:42 | object creation of type List : List | ArrayFlow.cs:210:63:210:69 | access to indexer | $@ | ArrayFlow.cs:210:63:210:69 | access to indexer | access to indexer | +| ArrayFlow.cs:84:17:84:23 | object creation of type A : A | ArrayFlow.cs:84:17:84:23 | object creation of type A : A | ArrayFlow.cs:87:14:87:20 | access to indexer | $@ | ArrayFlow.cs:87:14:87:20 | access to indexer | access to indexer | +| ArrayFlow.cs:84:17:84:23 | object creation of type A : A | ArrayFlow.cs:84:17:84:23 | object creation of type A : A | ArrayFlow.cs:89:14:89:28 | call to method ListFirst | $@ | ArrayFlow.cs:89:14:89:28 | call to method ListFirst | call to method ListFirst | +| ArrayFlow.cs:84:17:84:23 | object creation of type A : A | ArrayFlow.cs:84:17:84:23 | object creation of type A : A | ArrayFlow.cs:210:63:210:69 | access to indexer | $@ | ArrayFlow.cs:210:63:210:69 | access to indexer | access to indexer | +| ArrayFlow.cs:85:20:85:32 | object creation of type List : List | ArrayFlow.cs:85:20:85:32 | object creation of type List : List | ArrayFlow.cs:87:14:87:20 | access to indexer | $@ | ArrayFlow.cs:87:14:87:20 | access to indexer | access to indexer | +| ArrayFlow.cs:85:20:85:32 | object creation of type List : List | ArrayFlow.cs:85:20:85:32 | object creation of type List : List | ArrayFlow.cs:89:14:89:28 | call to method ListFirst | $@ | ArrayFlow.cs:89:14:89:28 | call to method ListFirst | call to method ListFirst | +| ArrayFlow.cs:85:20:85:32 | object creation of type List : List | ArrayFlow.cs:85:20:85:32 | object creation of type List : List | ArrayFlow.cs:210:63:210:69 | access to indexer | $@ | ArrayFlow.cs:210:63:210:69 | access to indexer | access to indexer | +| ArrayFlow.cs:94:20:94:32 | object creation of type List : List | ArrayFlow.cs:94:20:94:32 | object creation of type List : List | ArrayFlow.cs:96:14:96:20 | access to indexer | $@ | ArrayFlow.cs:96:14:96:20 | access to indexer | access to indexer | +| ArrayFlow.cs:94:20:94:32 | object creation of type List : List | ArrayFlow.cs:94:20:94:32 | object creation of type List : List | ArrayFlow.cs:98:14:98:28 | call to method ListFirst | $@ | ArrayFlow.cs:98:14:98:28 | call to method ListFirst | call to method ListFirst | +| ArrayFlow.cs:94:20:94:32 | object creation of type List : List | ArrayFlow.cs:94:20:94:32 | object creation of type List : List | ArrayFlow.cs:210:63:210:69 | access to indexer | $@ | ArrayFlow.cs:210:63:210:69 | access to indexer | access to indexer | +| ArrayFlow.cs:103:17:103:23 | object creation of type A : A | ArrayFlow.cs:103:17:103:23 | object creation of type A : A | ArrayFlow.cs:106:14:106:20 | access to indexer | $@ | ArrayFlow.cs:106:14:106:20 | access to indexer | access to indexer | +| ArrayFlow.cs:103:17:103:23 | object creation of type A : A | ArrayFlow.cs:103:17:103:23 | object creation of type A : A | ArrayFlow.cs:108:14:108:34 | call to method DictFirstValueA | $@ | ArrayFlow.cs:108:14:108:34 | call to method DictFirstValueA | call to method DictFirstValueA | +| ArrayFlow.cs:103:17:103:23 | object creation of type A : A | ArrayFlow.cs:103:17:103:23 | object creation of type A : A | ArrayFlow.cs:110:14:110:34 | call to method DictFirstValueC | $@ | ArrayFlow.cs:110:14:110:34 | call to method DictFirstValueC | call to method DictFirstValueC | +| ArrayFlow.cs:103:17:103:23 | object creation of type A : A | ArrayFlow.cs:103:17:103:23 | object creation of type A : A | ArrayFlow.cs:212:75:212:81 | access to indexer | $@ | ArrayFlow.cs:212:75:212:81 | access to indexer | access to indexer | +| ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:106:14:106:20 | access to indexer | $@ | ArrayFlow.cs:106:14:106:20 | access to indexer | access to indexer | +| ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:108:14:108:34 | call to method DictFirstValueA | $@ | ArrayFlow.cs:108:14:108:34 | call to method DictFirstValueA | call to method DictFirstValueA | +| ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:110:14:110:34 | call to method DictFirstValueC | $@ | ArrayFlow.cs:110:14:110:34 | call to method DictFirstValueC | call to method DictFirstValueC | +| ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:212:75:212:81 | access to indexer | $@ | ArrayFlow.cs:212:75:212:81 | access to indexer | access to indexer | +| ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:117:14:117:20 | access to indexer | $@ | ArrayFlow.cs:117:14:117:20 | access to indexer | access to indexer | +| ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:119:14:119:34 | call to method DictFirstValueA | $@ | ArrayFlow.cs:119:14:119:34 | call to method DictFirstValueA | call to method DictFirstValueA | +| ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:121:14:121:34 | call to method DictFirstValueC | $@ | ArrayFlow.cs:121:14:121:34 | call to method DictFirstValueC | call to method DictFirstValueC | +| ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:212:75:212:81 | access to indexer | $@ | ArrayFlow.cs:212:75:212:81 | access to indexer | access to indexer | +| ArrayFlow.cs:126:17:126:23 | object creation of type A : A | ArrayFlow.cs:126:17:126:23 | object creation of type A : A | ArrayFlow.cs:128:14:128:20 | access to indexer | $@ | ArrayFlow.cs:128:14:128:20 | access to indexer | access to indexer | +| ArrayFlow.cs:126:17:126:23 | object creation of type A : A | ArrayFlow.cs:126:17:126:23 | object creation of type A : A | ArrayFlow.cs:130:14:130:34 | call to method DictFirstValueA | $@ | ArrayFlow.cs:130:14:130:34 | call to method DictFirstValueA | call to method DictFirstValueA | +| ArrayFlow.cs:126:17:126:23 | object creation of type A : A | ArrayFlow.cs:126:17:126:23 | object creation of type A : A | ArrayFlow.cs:132:14:132:34 | call to method DictFirstValueC | $@ | ArrayFlow.cs:132:14:132:34 | call to method DictFirstValueC | call to method DictFirstValueC | +| ArrayFlow.cs:126:17:126:23 | object creation of type A : A | ArrayFlow.cs:126:17:126:23 | object creation of type A : A | ArrayFlow.cs:212:75:212:81 | access to indexer | $@ | ArrayFlow.cs:212:75:212:81 | access to indexer | access to indexer | +| ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:128:14:128:20 | access to indexer | $@ | ArrayFlow.cs:128:14:128:20 | access to indexer | access to indexer | +| ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:130:14:130:34 | call to method DictFirstValueA | $@ | ArrayFlow.cs:130:14:130:34 | call to method DictFirstValueA | call to method DictFirstValueA | +| ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:132:14:132:34 | call to method DictFirstValueC | $@ | ArrayFlow.cs:132:14:132:34 | call to method DictFirstValueC | call to method DictFirstValueC | +| ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:212:75:212:81 | access to indexer | $@ | ArrayFlow.cs:212:75:212:81 | access to indexer | access to indexer | +| ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:138:14:138:20 | access to indexer | $@ | ArrayFlow.cs:138:14:138:20 | access to indexer | access to indexer | +| ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:140:14:140:34 | call to method DictFirstValueA | $@ | ArrayFlow.cs:140:14:140:34 | call to method DictFirstValueA | call to method DictFirstValueA | +| ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:142:14:142:34 | call to method DictFirstValueC | $@ | ArrayFlow.cs:142:14:142:34 | call to method DictFirstValueC | call to method DictFirstValueC | +| ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:212:75:212:81 | access to indexer | $@ | ArrayFlow.cs:212:75:212:81 | access to indexer | access to indexer | +| ArrayFlow.cs:166:17:166:23 | object creation of type A : A | ArrayFlow.cs:166:17:166:23 | object creation of type A : A | ArrayFlow.cs:169:18:169:18 | access to local variable x | $@ | ArrayFlow.cs:169:18:169:18 | access to local variable x | access to local variable x | +| ArrayFlow.cs:181:17:181:23 | object creation of type A : A | ArrayFlow.cs:181:17:181:23 | object creation of type A : A | ArrayFlow.cs:185:18:185:35 | access to property Current | $@ | ArrayFlow.cs:185:18:185:35 | access to property Current | access to property Current | diff --git a/csharp/ql/test/library-tests/dataflow/arrays/ArrayFlow.ql b/csharp/ql/test/library-tests/dataflow/arrays/ArrayFlow.ql new file mode 100644 index 00000000000..d1290562252 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/arrays/ArrayFlow.ql @@ -0,0 +1,23 @@ +/** + * @kind path-problem + */ + +import csharp +import DataFlow::PathGraph + +class Conf extends TaintTracking::Configuration { + Conf() { this = "ArrayFlowConf" } + + override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ObjectCreation } + + override predicate isSink(DataFlow::Node sink) { + exists(MethodCall mc | + mc.getTarget().hasName("Sink") and + mc.getAnArgument() = sink.asExpr() + ) + } +} + +from DataFlow::PathNode source, DataFlow::PathNode sink, Conf conf +where conf.hasFlowPath(source, sink) +select source, source, sink, "$@", sink, sink.toString() From 427c32f2116ac9f8440dbe69540e7fc2ce53e185 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 17 Apr 2020 11:25:23 +0200 Subject: [PATCH 0170/1298] report a local variable as the misspelling if there any many occourances of the global --- .../src/Expressions/MisspelledVariableName.ql | 37 +++++++++++++++++-- .../MisspelledVariableName.expected | 12 +++++- .../Expressions/MisspelledVariableName/tst.js | 12 ++++++ 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/Expressions/MisspelledVariableName.ql b/javascript/ql/src/Expressions/MisspelledVariableName.ql index ce5dc546341..9eeeb288134 100644 --- a/javascript/ql/src/Expressions/MisspelledVariableName.ql +++ b/javascript/ql/src/Expressions/MisspelledVariableName.ql @@ -14,6 +14,37 @@ import Misspelling -from GlobalVarAccess gva, VarDecl lvd -where misspelledVariableName(gva, lvd) -select gva, "'" + gva + "' may be a typo for variable $@.", lvd, lvd.getName() +/** + * Gets the number of times a local variable with name `name` occurs in the program. + */ +bindingset[name] +int localAcceses(string name) { + result = count(VarAccess acc | acc.getName() = name and not acc instanceof GlobalVarAccess) +} + +/** + * Gets the number of times a global variable with name `name` occurs in the program. + */ +bindingset[name] +int globalAccesses(string name) { result = count(GlobalVarAccess acc | acc.getName() = name) } + +/** + * Holds if our heuristic says that the local variable `lvd` seems to be a misspelling of the global variable `gvd`. + * Otherwise the global variable is likely the misspelling. + */ +predicate globalIsLikelyCorrect(GlobalVarAccess gva, VarDecl lvd) { + // If there are more occurrences of the global (by a margin of at least 2), and the local is missing one letter compared to the global. + globalAccesses(gva.getName()) >= localAcceses(lvd.getName()) + 2 and + lvd.getName().length() = gva.getName().length() - 1 + or + // Or if there are many more of the global. + globalAccesses(gva.getName()) > 2 * localAcceses(lvd.getName()) + 2 +} + +from GlobalVarAccess gva, VarDecl lvd, string msg +where + misspelledVariableName(gva, lvd) and + if globalIsLikelyCorrect(gva, lvd) + then msg = "$@ may be a typo for '" + gva + "'." + else msg = "'" + gva + "' may be a typo for variable $@." +select gva, msg, lvd, lvd.getName() diff --git a/javascript/ql/test/query-tests/Expressions/MisspelledVariableName/MisspelledVariableName.expected b/javascript/ql/test/query-tests/Expressions/MisspelledVariableName/MisspelledVariableName.expected index 43098d60483..535682017e4 100644 --- a/javascript/ql/test/query-tests/Expressions/MisspelledVariableName/MisspelledVariableName.expected +++ b/javascript/ql/test/query-tests/Expressions/MisspelledVariableName/MisspelledVariableName.expected @@ -1,5 +1,13 @@ | MisspelledVariableName.js:2:40:2:45 | lenght | 'lenght' may be a typo for variable $@. | MisspelledVariableName.js:2:19:2:24 | length | length | | tst.js:2:10:2:20 | errorMesage | 'errorMesage' may be a typo for variable $@. | tst.js:1:12:1:23 | errorMessage | errorMessage | -| tst.js:6:10:6:21 | errorMessage | 'errorMessage' may be a typo for variable $@. | tst.js:5:12:5:22 | errorMesage | errorMesage | +| tst.js:6:10:6:21 | errorMessage | $@ may be a typo for 'errorMessage'. | tst.js:5:12:5:22 | errorMesage | errorMesage | | tst.js:11:12:11:22 | errorMesage | 'errorMesage' may be a typo for variable $@. | tst.js:9:12:9:23 | errorMessage | errorMessage | -| tst.js:17:5:17:16 | errorMessage | 'errorMessage' may be a typo for variable $@. | tst.js:15:12:15:22 | errorMesage | errorMesage | +| tst.js:17:5:17:16 | errorMessage | $@ may be a typo for 'errorMessage'. | tst.js:15:12:15:22 | errorMesage | errorMesage | +| tst.js:22:2:22:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander | +| tst.js:23:2:23:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander | +| tst.js:24:2:24:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander | +| tst.js:25:2:25:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander | +| tst.js:26:2:26:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander | +| tst.js:27:2:27:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander | +| tst.js:28:2:28:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander | +| tst.js:29:2:29:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander | diff --git a/javascript/ql/test/query-tests/Expressions/MisspelledVariableName/tst.js b/javascript/ql/test/query-tests/Expressions/MisspelledVariableName/tst.js index bc669b52957..cd6c027f1fc 100644 --- a/javascript/ql/test/query-tests/Expressions/MisspelledVariableName/tst.js +++ b/javascript/ql/test/query-tests/Expressions/MisspelledVariableName/tst.js @@ -16,3 +16,15 @@ function k(errorMesage) { let inner = () => errorMessage; } + +function foo() { + var thisHander; + thisHandler.foo1; + thisHandler.foo2; + thisHandler.foo3; + thisHandler.foo4; + thisHandler.foo5; + thisHandler.foo6; + thisHandler.foo7; + thisHandler.foo8; +} \ No newline at end of file From 4f32157a787b36cc34b91d654c3cf0b2b41551d7 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 17 Apr 2020 11:36:48 +0200 Subject: [PATCH 0171/1298] rename `func` to `callback` Co-Authored-By: Esben Sparre Andreasen --- .../ql/src/semmle/javascript/frameworks/NodeJSLib.qll | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll index 3437aa09830..fadc30ded07 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll @@ -587,15 +587,15 @@ module NodeJSLib { } /** - * Gets a possibly promisified (using `util.promisify`) version of the input `func`. + * Gets a possibly promisified (using `util.promisify`) version of the input `callback`. */ - DataFlow::SourceNode maybePromisified(DataFlow::SourceNode func) { - result = func + DataFlow::SourceNode maybePromisified(DataFlow::SourceNode callback) { + result = callback or exists(DataFlow::CallNode promisify | promisify = DataFlow::moduleMember("util", "promisify").getACall() | - result = promisify and promisify.getArgument(0).getALocalSource() = func + result = promisify and promisify.getArgument(0).getALocalSource() = callback ) } From 3b230648d2de64a91a2a4dfec774c5ea86e70509 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 17 Apr 2020 11:45:08 +0200 Subject: [PATCH 0172/1298] change-note --- change-notes/1.24/analysis-javascript.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/change-notes/1.24/analysis-javascript.md b/change-notes/1.24/analysis-javascript.md index 0e92d66033d..b6ba0099c14 100644 --- a/change-notes/1.24/analysis-javascript.md +++ b/change-notes/1.24/analysis-javascript.md @@ -87,6 +87,8 @@ | Identical operands (`js/redundant-operation`) | Fewer results | This query now recognizes cases where the operands change a value using ++/-- expressions. | | Superfluous trailing arguments (`js/superfluous-trailing-arguments`) | Fewer results | This query now recognizes cases where a function uses the `Function.arguments` value to process a variable number of parameters. | | Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes more variations of URL scheme checks. | +| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes more file system calls. | +| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes more command execution calls. | ## Changes to libraries From 4a93b91d59391278cbd675a8c064166724b3e2dc Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 17 Apr 2020 11:47:03 +0200 Subject: [PATCH 0173/1298] make maybePromisified private --- javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll index fadc30ded07..e368b16e433 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll @@ -589,7 +589,7 @@ module NodeJSLib { /** * Gets a possibly promisified (using `util.promisify`) version of the input `callback`. */ - DataFlow::SourceNode maybePromisified(DataFlow::SourceNode callback) { + private DataFlow::SourceNode maybePromisified(DataFlow::SourceNode callback) { result = callback or exists(DataFlow::CallNode promisify | From 8c03423f3e88e847a19a3ec0bfa873d334414601 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 17 Apr 2020 12:03:16 +0200 Subject: [PATCH 0174/1298] C++: Accept test output --- .../dataflow/dataflow-tests/test_diff.expected | 7 ------- .../library-tests/dataflow/dataflow-tests/test_ir.expected | 7 +++++++ .../library-tests/dataflow/taint-tests/test_diff.expected | 1 - .../library-tests/dataflow/taint-tests/test_ir.expected | 1 + 4 files changed, 8 insertions(+), 8 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..9bad6e02bcc 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 | @@ -45,9 +41,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 275cbabc075..35068c56232 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 | @@ -61,6 +65,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/taint-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected index af9d002dcdc..3be23cbcc40 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 @@ -28,7 +28,6 @@ | 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 9dc1088434c..b44e17882e7 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 @@ -12,6 +12,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 08d1a2c5ea584131304885223ee3fc621139b920 Mon Sep 17 00:00:00 2001 From: Felicity Chapman Date: Fri, 17 Apr 2020 11:30:18 +0100 Subject: [PATCH 0175/1298] Reorder table and remove empty sections --- change-notes/1.24/analysis-csharp.md | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/change-notes/1.24/analysis-csharp.md b/change-notes/1.24/analysis-csharp.md index a745e985eae..31ababc562f 100644 --- a/change-notes/1.24/analysis-csharp.md +++ b/change-notes/1.24/analysis-csharp.md @@ -17,15 +17,13 @@ The following changes in version 1.24 affect C# analysis in all applications. | **Query** | **Expected impact** | **Change** | |------------------------------|------------------------|-----------------------------------| -| Useless assignment to local variable (`cs/useless-assignment-to-local`) | Fewer false positive results | Results have been removed when the variable is named `_` in a `foreach` statement. | -| Potentially dangerous use of non-short-circuit logic (`cs/non-short-circuit`) | Fewer false positive results | Results have been removed when the expression contains an `out` parameter. | | Dereferenced variable may be null (`cs/dereferenced-value-may-be-null`) | More results | Results are reported from parameters with a default value of `null`. | -| Useless assignment to local variable (`cs/useless-assignment-to-local`) | Fewer false positive results | Results have been removed when the value assigned is an (implicitly or explicitly) cast default-like value. For example, `var s = (string)null` and `string s = default`. | -| XPath injection (`cs/xml/xpath-injection`) | More results | The query now recognizes calls to methods on `System.Xml.XPath.XPathNavigator` objects. | -| Information exposure through transmitted data (`cs/sensitive-data-transmission`) | More results | The query now recognizes writes to cookies and writes to ASP.NET (`Inner`)`Text` properties as additional sinks. | | Information exposure through an exception (`cs/information-exposure-through-exception`) | More results | The query now recognizes writes to cookies, writes to ASP.NET (`Inner`)`Text` properties, and email contents as additional sinks. | - -## Removal of old queries +| Information exposure through transmitted data (`cs/sensitive-data-transmission`) | More results | The query now recognizes writes to cookies and writes to ASP.NET (`Inner`)`Text` properties as additional sinks. | +| Potentially dangerous use of non-short-circuit logic (`cs/non-short-circuit`) | Fewer false positive results | Results have been removed when the expression contains an `out` parameter. | +| Useless assignment to local variable (`cs/useless-assignment-to-local`) | Fewer false positive results | Results have been removed when the value assigned is an (implicitly or explicitly) cast default-like value. For example, `var s = (string)null` and `string s = default`. | +| Useless assignment to local variable (`cs/useless-assignment-to-local`) | Fewer false positive results | Results have been removed when the variable is named `_` in a `foreach` statement. | +| XPath injection (`cs/xml/xpath-injection`) | More results | The query now recognizes calls to methods on `System.Xml.XPath.XPathNavigator` objects. | ## Changes to code extraction @@ -37,13 +35,11 @@ The following changes in version 1.24 affect C# analysis in all applications. ## Changes to libraries * The data-flow library has been improved, which affects and improves most security queries. The improvements are: - - Track flow through methods that combine taint tracking with flow through fields. - - Track flow through clone-like methods, that is, methods that read contents of a field from a - parameter and stores the value in the field of a returned object. + - Track flow through methods that combine taint tracking with flow through fields. + - Track flow through clone-like methods, that is, methods that read contents of a field from a + parameter and stores the value in the field of a returned object. * The taint tracking library now tracks flow through (implicit or explicit) conversion operator calls. * [Code contracts](https://docs.microsoft.com/en-us/dotnet/framework/debug-trace-profile/code-contracts) are now recognized, and are treated like any other assertion methods. * Expression nullability flow state is given by the predicates `Expr.hasNotNullFlowState()` and `Expr.hasMaybeNullFlowState()`. * `stackalloc` array creations are now represented by the QL class `Stackalloc`. Previously they were represented by the class `ArrayCreation`. * A new class `RemoteFlowSink` has been added to model sinks where data might be exposed to external users. Examples include web page output, e-mails, and cookies. - -## Changes to autobuilder From 81b3b4884c1712239a4bdea06b10f72abdf2bfe5 Mon Sep 17 00:00:00 2001 From: Felicity Chapman Date: Fri, 17 Apr 2020 11:33:48 +0100 Subject: [PATCH 0176/1298] Add LGTM info for new queries and comment detail Plus minor editorial changes --- change-notes/1.24/analysis-csharp.md | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/change-notes/1.24/analysis-csharp.md b/change-notes/1.24/analysis-csharp.md index 31ababc562f..3ed64a6b27b 100644 --- a/change-notes/1.24/analysis-csharp.md +++ b/change-notes/1.24/analysis-csharp.md @@ -2,16 +2,20 @@ The following changes in version 1.24 affect C# analysis in all applications. +## General improvements + +You can now suppress alerts using either single-line block comments (`/* ... */`) or line comments (`// ...`). + ## New queries | **Query** | **Tags** | **Purpose** | |-----------------------------|-----------|--------------------------------------------------------------------| -| Assembly path injection (`cs/assembly-path-injection`) | security, external/cwe/cwe-114 | Finds user-controlled data used to load an assembly. | -| Insecure configuration for ASP.NET requestValidationMode (`cs/insecure-request-validation-mode`) | security, external/cwe/cwe-016 | Finds where this attribute has been set to a value less than 4.5, which turns off some validation features and makes the application less secure. | -| Insecure SQL connection (`cs/insecure-sql-connection`) | security, external/cwe/cwe-327 | Finds unencrypted SQL connection strings. | -| Page request validation is disabled (`cs/web/request-validation-disabled`) | security, frameworks/asp.net, external/cwe/cwe-016 | Finds where ASP.NET page request validation has been disabled, which could make the application less secure. | -| Serialization check bypass (`cs/serialization-check-bypass`) | security, external/cwe/cwe-20 | Finds where data is not validated in a deserialization method. | -| XML injection (`cs/xml-injection`) | security, external/cwe/cwe-091 | Finds user-controlled data that is used to write directly to an XML document. | +| Assembly path injection (`cs/assembly-path-injection`) | security, external/cwe/cwe-114 | Finds user-controlled data used to load an assembly. Results are shown on LGTM by default. | +| Insecure configuration for ASP.NET requestValidationMode (`cs/insecure-request-validation-mode`) | security, external/cwe/cwe-016 | Finds where this attribute has been set to a value less than 4.5, which turns off some validation features and makes the application less secure. By default, the query is not run on LGTM. | +| Insecure SQL connection (`cs/insecure-sql-connection`) | security, external/cwe/cwe-327 | Finds unencrypted SQL connection strings. Results are not shown on LGTM by default. | +| Page request validation is disabled (`cs/web/request-validation-disabled`) | security, frameworks/asp.net, external/cwe/cwe-016 | Finds where ASP.NET page request validation has been disabled, which could make the application less secure. By default, the query is not run on LGTM. | +| Serialization check bypass (`cs/serialization-check-bypass`) | security, external/cwe/cwe-20 | Finds where data is not validated in a deserialization method. Results are not shown on LGTM by default. | +| XML injection (`cs/xml-injection`) | security, external/cwe/cwe-091 | Finds user-controlled data that is used to write directly to an XML document. Results are shown on LGTM by default. | ## Changes to existing queries @@ -21,8 +25,7 @@ The following changes in version 1.24 affect C# analysis in all applications. | Information exposure through an exception (`cs/information-exposure-through-exception`) | More results | The query now recognizes writes to cookies, writes to ASP.NET (`Inner`)`Text` properties, and email contents as additional sinks. | | Information exposure through transmitted data (`cs/sensitive-data-transmission`) | More results | The query now recognizes writes to cookies and writes to ASP.NET (`Inner`)`Text` properties as additional sinks. | | Potentially dangerous use of non-short-circuit logic (`cs/non-short-circuit`) | Fewer false positive results | Results have been removed when the expression contains an `out` parameter. | -| Useless assignment to local variable (`cs/useless-assignment-to-local`) | Fewer false positive results | Results have been removed when the value assigned is an (implicitly or explicitly) cast default-like value. For example, `var s = (string)null` and `string s = default`. | -| Useless assignment to local variable (`cs/useless-assignment-to-local`) | Fewer false positive results | Results have been removed when the variable is named `_` in a `foreach` statement. | +| Useless assignment to local variable (`cs/useless-assignment-to-local`) | Fewer false positive results | Results have been removed when the value assigned is an (implicitly or explicitly) cast default-like value. For example, `var s = (string)null` and `string s = default`. Results have also been removed when the variable is named `_` in a `foreach` statement. | | XPath injection (`cs/xml/xpath-injection`) | More results | The query now recognizes calls to methods on `System.Xml.XPath.XPathNavigator` objects. | ## Changes to code extraction @@ -36,10 +39,10 @@ The following changes in version 1.24 affect C# analysis in all applications. * The data-flow library has been improved, which affects and improves most security queries. The improvements are: - Track flow through methods that combine taint tracking with flow through fields. - - Track flow through clone-like methods, that is, methods that read contents of a field from a - parameter and stores the value in the field of a returned object. + - Track flow through clone-like methods, that is, methods that read the contents of a field from a + parameter and store the value in the field of a returned object. * The taint tracking library now tracks flow through (implicit or explicit) conversion operator calls. * [Code contracts](https://docs.microsoft.com/en-us/dotnet/framework/debug-trace-profile/code-contracts) are now recognized, and are treated like any other assertion methods. * Expression nullability flow state is given by the predicates `Expr.hasNotNullFlowState()` and `Expr.hasMaybeNullFlowState()`. * `stackalloc` array creations are now represented by the QL class `Stackalloc`. Previously they were represented by the class `ArrayCreation`. -* A new class `RemoteFlowSink` has been added to model sinks where data might be exposed to external users. Examples include web page output, e-mails, and cookies. +* A new class `RemoteFlowSink` has been added to model sinks where data might be exposed to external users. Examples include web page output, emails, and cookies. From e72eed1db5b9364104c5d72ceabe3c365f494473 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 17 Apr 2020 13:10:06 +0200 Subject: [PATCH 0177/1298] more -> additional Co-Authored-By: Esben Sparre Andreasen --- change-notes/1.24/analysis-javascript.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/change-notes/1.24/analysis-javascript.md b/change-notes/1.24/analysis-javascript.md index b6ba0099c14..e3f7e920848 100644 --- a/change-notes/1.24/analysis-javascript.md +++ b/change-notes/1.24/analysis-javascript.md @@ -86,9 +86,9 @@ | Useless regular-expression character escape (`js/useless-regexp-character-escape`) | Fewer false positive results | This query now distinguishes escapes in strings and regular expression literals. | | Identical operands (`js/redundant-operation`) | Fewer results | This query now recognizes cases where the operands change a value using ++/-- expressions. | | Superfluous trailing arguments (`js/superfluous-trailing-arguments`) | Fewer results | This query now recognizes cases where a function uses the `Function.arguments` value to process a variable number of parameters. | -| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes more variations of URL scheme checks. | -| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes more file system calls. | -| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes more command execution calls. | +| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional variations of URL scheme checks. | +| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. | +| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. | ## Changes to libraries From 67e8a5c8d87f20913f2a3cd275266a5add99a7b2 Mon Sep 17 00:00:00 2001 From: Felicity Chapman Date: Fri, 17 Apr 2020 11:41:03 +0100 Subject: [PATCH 0178/1298] Minor editorial changes --- change-notes/1.24/analysis-java.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/change-notes/1.24/analysis-java.md b/change-notes/1.24/analysis-java.md index 36210c0457e..a594cf08e1e 100644 --- a/change-notes/1.24/analysis-java.md +++ b/change-notes/1.24/analysis-java.md @@ -4,7 +4,7 @@ The following changes in version 1.24 affect Java analysis in all applications. ## General improvements -* Alert suppression can now be done with single-line block comments (`/* ... */`) as well as line comments (`// ...`). +* You can now suppress alerts using either single-line block comments (`/* ... */`) or line comments (`// ...`). * A `Customizations.qll` file has been added to allow customizations of the standard library that apply to all queries. ## New queries @@ -21,16 +21,16 @@ The following changes in version 1.24 affect Java analysis in all applications. | **Query** | **Expected impact** | **Change** | |------------------------------|------------------------|-----------------------------------| -| Dereferenced variable may be null (`java/dereferenced-value-may-be-null`) | Fewer false positives | Final fields with a non-null initializer are no longer reported. | -| Expression always evaluates to the same value (`java/evaluation-to-constant`) | Fewer false positives | Expressions of the form `0 * x` are usually intended and no longer reported. Also left shift of ints by 32 bits and longs by 64 bits are no longer reported as they are not constant, these results are instead reported by the new query `java/lshift-larger-than-type-width`. | -| Useless null check (`java/useless-null-check`) | More true positives | Useless checks on final fields with a non-null initializer are now reported. | +| Dereferenced variable may be null (`java/dereferenced-value-may-be-null`) | Fewer false positive results | Final fields with a non-null initializer are no longer reported. | +| Expression always evaluates to the same value (`java/evaluation-to-constant`) | Fewer false positive results | Expressions of the form `0 * x` are usually intended and no longer reported. Also left shift of ints by 32 bits and longs by 64 bits are no longer reported as they are not constant, these results are instead reported by the new query `java/lshift-larger-than-type-width`. | +| Useless null check (`java/useless-null-check`) | More true positive results | Useless checks on final fields with a non-null initializer are now reported. | ## Changes to libraries * The data-flow library has been improved, which affects and improves most security queries. The improvements are: - - Track flow through methods that combine taint tracking with flow through fields. - - Track flow through clone-like methods, that is, methods that read contents of a field from a - parameter and stores the value in the field of a returned object. + - Track flow through methods that combine taint tracking with flow through fields. + - Track flow through clone-like methods, that is, methods that read contents of a field from a + parameter and stores the value in the field of a returned object. * Identification of test classes has been improved. Previously, one of the match conditions would classify any class with a name containing the string "Test" as a test class, but now this matching has been replaced with one that @@ -38,6 +38,6 @@ The following changes in version 1.24 affect Java analysis in all applications. general file classification mechanism and thus suppression of alerts, and also any security queries using taint tracking, as test classes act as default barriers stopping taint flow. -* Parentheses are now no longer modelled directly in the AST, that is, the +* Parentheses are now no longer modeled directly in the AST, that is, the `ParExpr` class is empty. Instead, a parenthesized expression can be identified with the `Expr.isParenthesized()` member predicate. From ee12e6a00bf5b2dfc4939d7082206c6816e9f97f Mon Sep 17 00:00:00 2001 From: Felicity Chapman Date: Fri, 17 Apr 2020 12:35:33 +0100 Subject: [PATCH 0179/1298] Sort alphabetically --- change-notes/1.24/analysis-javascript.md | 93 ++++++++++++------------ 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/change-notes/1.24/analysis-javascript.md b/change-notes/1.24/analysis-javascript.md index 0e92d66033d..b884fa4b66d 100644 --- a/change-notes/1.24/analysis-javascript.md +++ b/change-notes/1.24/analysis-javascript.md @@ -7,10 +7,10 @@ * Alert suppression can now be done with single-line block comments (`/* ... */`) as well as line comments (`// ...`). * Resolution of imports has improved, leading to more results from the security queries: - - Imports with the `.js` extension can now be resolved to a TypeScript file, - when the import refers to a file generated by TypeScript. - - Imports that rely on path-mappings from a `tsconfig.json` file can now be resolved. - - Export declarations of the form `export * as ns from "x"` are now analyzed more precisely. + - Imports with the `.js` extension can now be resolved to a TypeScript file, + when the import refers to a file generated by TypeScript. + - Imports that rely on path-mappings from a `tsconfig.json` file can now be resolved. + - Export declarations of the form `export * as ns from "x"` are now analyzed more precisely. * The analysis of sanitizers has improved, leading to more accurate results from the security queries. In particular: @@ -24,47 +24,48 @@ * Support for flow summaries has been more clearly marked as being experimental and moved to the new `experimental` folder. * Support for the following frameworks and libraries has been improved: - - [Electron](https://electronjs.org/) - - [fstream](https://www.npmjs.com/package/fstream) - - [Handlebars](https://www.npmjs.com/package/handlebars) - - [jsonfile](https://www.npmjs.com/package/jsonfile) - - [Koa](https://www.npmjs.com/package/koa) - - [Node.js](https://nodejs.org/) - - [Socket.IO](https://socket.io/) - - [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) - - [chrome-remote-interface](https://www.npmjs.com/package/chrome-remote-interface) - - [for-in](https://www.npmjs.com/package/for-in) - - [for-own](https://www.npmjs.com/package/for-own) - - [http2](https://nodejs.org/api/http2.html) - - [jQuery](https://jquery.com/) - - [lazy-cache](https://www.npmjs.com/package/lazy-cache) - - [mongodb](https://www.npmjs.com/package/mongodb) - - [ncp](https://www.npmjs.com/package/ncp) - - [node-dir](https://www.npmjs.com/package/node-dir) - - [path-exists](https://www.npmjs.com/package/path-exists) - - [pg](https://www.npmjs.com/package/pg) - - [react](https://www.npmjs.com/package/react) - - [recursive-readdir](https://www.npmjs.com/package/recursive-readdir) - - [request](https://www.npmjs.com/package/request) - - [rimraf](https://www.npmjs.com/package/rimraf) - - [send](https://www.npmjs.com/package/send) - - [SockJS](https://www.npmjs.com/package/sockjs) - - [SockJS-client](https://www.npmjs.com/package/sockjs-client) - - [typeahead.js](https://www.npmjs.com/package/typeahead.js) - - [vinyl-fs](https://www.npmjs.com/package/vinyl-fs) - - [write-file-atomic](https://www.npmjs.com/package/write-file-atomic) - - [ws](https://github.com/websockets/ws) + - [chrome-remote-interface](https://www.npmjs.com/package/chrome-remote-interface) + - [Electron](https://electronjs.org/) + - [for-in](https://www.npmjs.com/package/for-in) + - [for-own](https://www.npmjs.com/package/for-own) + - [fstream](https://www.npmjs.com/package/fstream) + - [Handlebars](https://www.npmjs.com/package/handlebars) + - [http2](https://nodejs.org/api/http2.html) + - [jQuery](https://jquery.com/) + - [jsonfile](https://www.npmjs.com/package/jsonfile) + - [Koa](https://www.npmjs.com/package/koa) + - [lazy-cache](https://www.npmjs.com/package/lazy-cache) + - [mongodb](https://www.npmjs.com/package/mongodb) + - [ncp](https://www.npmjs.com/package/ncp) + - [Node.js](https://nodejs.org/) + - [node-dir](https://www.npmjs.com/package/node-dir) + - [path-exists](https://www.npmjs.com/package/path-exists) + - [pg](https://www.npmjs.com/package/pg) + - [react](https://www.npmjs.com/package/react) + - [recursive-readdir](https://www.npmjs.com/package/recursive-readdir) + - [request](https://www.npmjs.com/package/request) + - [rimraf](https://www.npmjs.com/package/rimraf) + - [send](https://www.npmjs.com/package/send) + - [Socket.IO](https://socket.io/) + - [SockJS](https://www.npmjs.com/package/sockjs) + - [SockJS-client](https://www.npmjs.com/package/sockjs-client) + - [typeahead.js](https://www.npmjs.com/package/typeahead.js) + - [vinyl-fs](https://www.npmjs.com/package/vinyl-fs) + - [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) + - [write-file-atomic](https://www.npmjs.com/package/write-file-atomic) + - [ws](https://github.com/websockets/ws) + ## New queries | **Query** | **Tags** | **Purpose** | |---------------------------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Cross-site scripting through exception (`js/xss-through-exception`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities where an exception is written to the DOM. Results are not shown on LGTM by default. | -| Regular expression always matches (`js/regex/always-matches`) | correctness, regular-expressions | Highlights regular expression checks that trivially succeed by matching an empty substring. Results are shown on LGTM by default. | | Missing await (`js/missing-await`) | correctness | Highlights expressions that operate directly on a promise object in a nonsensical way, instead of awaiting its result. Results are shown on LGTM by default. | | Polynomial regular expression used on uncontrolled data (`js/polynomial-redos`) | security, external/cwe/cwe-730, external/cwe/cwe-400 | Highlights expensive regular expressions that may be used on malicious input. Results are shown on LGTM by default. | | Prototype pollution in utility function (`js/prototype-pollution-utility`) | security, external/cwe/cwe-400, external/cwe/cwe-471 | Highlights recursive assignment operations that are susceptible to prototype pollution. Results are shown on LGTM by default. | -| Unsafe jQuery plugin (`js/unsafe-jquery-plugin`) | Highlights potential XSS vulnerabilities in unsafely designed jQuery plugins. Results are shown on LGTM by default. | +| Regular expression always matches (`js/regex/always-matches`) | correctness, regular-expressions | Highlights regular expression checks that trivially succeed by matching an empty substring. Results are shown on LGTM by default. | +| Unsafe jQuery plugin (`js/unsafe-jquery-plugin`) | | Highlights potential XSS vulnerabilities in unsafely designed jQuery plugins. Results are shown on LGTM by default. | | Unnecessary use of `cat` process (`js/unnecessary-use-of-cat`) | correctness, security, maintainability | Highlights command executions of `cat` where the fs API should be used instead. Results are shown on LGTM by default. | @@ -74,19 +75,19 @@ |--------------------------------|------------------------------|---------------------------------------------------------------------------| | Clear-text logging of sensitive information (`js/clear-text-logging`) | More results | More results involving `process.env` and indirect calls to logging methods are recognized. | | Duplicate parameter names (`js/duplicate-parameter-name`) | Fewer results | This query now recognizes additional parameters that reasonably can have duplicated names. | -| Incomplete string escaping or encoding (`js/incomplete-sanitization`) | Fewer false positive results | This query now recognizes additional cases where a single replacement is likely to be intentional. | -| Unbound event handler receiver (`js/unbound-event-handler-receiver`) | Fewer false positive results | This query now recognizes additional ways event handler receivers can be bound. | | Expression has no effect (`js/useless-expression`) | Fewer false positive results | The query now recognizes block-level flow type annotations and ignores the first statement of a try block. | -| Use of call stack introspection in strict mode (`js/strict-mode-call-stack-introspection`) | Fewer false positive results | The query no longer flags expression statements. | +| Identical operands (`js/redundant-operation`) | Fewer results | This query now recognizes cases where the operands change a value using ++/-- expressions. | +| Incomplete string escaping or encoding (`js/incomplete-sanitization`) | Fewer false positive results | This query now recognizes additional cases where a single replacement is likely to be intentional. | +| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes more variations of URL scheme checks. | | Missing CSRF middleware (`js/missing-token-validation`) | Fewer false positive results | The query reports fewer duplicates and only flags handlers that explicitly access cookie data. | -| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional ways dangerous paths can be constructed and used. | -| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional ways of constructing arguments to `cmd.exe` and `/bin/sh`. | +| Superfluous trailing arguments (`js/superfluous-trailing-arguments`) | Fewer results | This query now recognizes cases where a function uses the `Function.arguments` value to process a variable number of parameters. | | Syntax error (`js/syntax-error`) | Lower severity | This results of this query are now displayed with lower severity. | +| Unbound event handler receiver (`js/unbound-event-handler-receiver`) | Fewer false positive results | This query now recognizes additional ways event handler receivers can be bound. | +| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional ways of constructing arguments to `cmd.exe` and `/bin/sh`. | +| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional ways dangerous paths can be constructed and used. | +| Use of call stack introspection in strict mode (`js/strict-mode-call-stack-introspection`) | Fewer false positive results | The query no longer flags expression statements. | | Use of password hash with insufficient computational effort (`js/insufficient-password-hash`) | Fewer false positive results | This query now recognizes additional cases that do not require secure hashing. | | Useless regular-expression character escape (`js/useless-regexp-character-escape`) | Fewer false positive results | This query now distinguishes escapes in strings and regular expression literals. | -| Identical operands (`js/redundant-operation`) | Fewer results | This query now recognizes cases where the operands change a value using ++/-- expressions. | -| Superfluous trailing arguments (`js/superfluous-trailing-arguments`) | Fewer results | This query now recognizes cases where a function uses the `Function.arguments` value to process a variable number of parameters. | -| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes more variations of URL scheme checks. | ## Changes to libraries @@ -94,6 +95,6 @@ * An extensible model of the `EventEmitter` pattern has been implemented. * Taint-tracking configurations now interact differently with the `data` flow label, which may affect queries that combine taint-tracking and flow labels. - - Sources added by the 1-argument `isSource` predicate are associated with the `taint` label now, instead of the `data` label. - - Sanitizers now only block the `taint` label. As a result, sanitizers no longer block the flow of tainted values wrapped inside a property of an object. + - Sources added by the 1-argument `isSource` predicate are associated with the `taint` label now, instead of the `data` label. + - Sanitizers now only block the `taint` label. As a result, sanitizers no longer block the flow of tainted values wrapped inside a property of an object. To retain the old behavior, instead use a barrier, or block the `data` flow label using a labeled sanitizer. From de41e668b0b1ca9b0f1390f0c74f2224f4dab340 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 12 Mar 2020 20:38:31 +0100 Subject: [PATCH 0180/1298] Data flow: No more flow summaries --- .../csharp/dataflow/internal/DataFlowImpl.qll | 1986 ++++++++--------- .../dataflow/internal/DataFlowImplCommon.qll | 459 ++-- 2 files changed, 1123 insertions(+), 1322 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index a1daeb66411..7a04c1f2a75 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -251,15 +251,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +289,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +368,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +379,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +506,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +543,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +557,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) + read(n1, f, n2) } pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) } -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) } pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and - nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) - ) -} - -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) -} - -pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) -} - -/** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +647,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,117 +659,126 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + store(mid, f, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, config) and + exists(Node mid, Content f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, unbind(config)) and + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,7 +1054,7 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or @@ -1292,7 +1062,7 @@ private module LocalFlowBigStep { node instanceof ParameterNode or node instanceof OutNode or node instanceof PostUpdateNode or - readDirect(_, _, node) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1072,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1086,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1109,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,307 +1146,365 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(config)) and +private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(node1, f, node2, config) and +private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) and nodeCand2(node1, config) and - nodeCand2(node2, _, true, unbind(config)) and - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(f, unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) + ) + or + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +pragma[nomagic] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) + ) +} + +/** + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. + */ +pragma[nomagic] +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and + toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) + ) + or + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + else returnApf = TAccessPathFrontNone() } pragma[nomagic] private predicate flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, + Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, apf0, config) and +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, apf, config) + ) +} + +pragma[nomagic] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +private newtype TAccessPathOption = + TAccessPathNone() or + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} + /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) -} - -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true ) } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) + ) +} + +/** + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. + */ +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + or + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and + ap instanceof AccessPathNil + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and + toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + ) + or + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() +} + +pragma[nomagic] +private predicate storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, f, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, ap0, unbind(config)) } pragma[nomagic] private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2050,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2303,7 +2240,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2255,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2347,7 +2284,7 @@ private predicate pathIntoLocalStep( pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2297,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2336,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2352,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2376,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2451,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2492,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2854,7 +2788,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll index 783ac641e6e..b241a574c97 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -26,13 +26,30 @@ private module Cached { ) } - /** Provides predicates for calculating flow-through summaries. */ + pragma[nomagic] + private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { + viableCallable(call) = result.getCallable() and + kind = result.getKind() + } + + /** + * Holds if a value at return position `pos` can be returned to `out` via `call`, + * taking virtual dispatch into account. + */ cached + predicate viableReturnPosOut(DataFlowCall call, ReturnPosition pos, Node out) { + exists(ReturnKindExt kind | + pos = viableReturnPos(call, kind) and + out = kind.getAnOutNode(call) + ) + } + + /** Provides predicates for calculating flow-through summaries. */ private module FlowThrough { /** * The first flow-through approximation: * - * - Input/output access paths are abstracted with a Boolean parameter + * - Input access paths are abstracted with a Boolean parameter * that indicates (non-)emptiness. */ private module Cand { @@ -40,83 +57,47 @@ private module Cached { * Holds if `p` can flow to `node` in the same callable using only * value-preserving steps. * - * `read` indicates whether it is contents of `p` that can flow to `node`, - * and `stored` indicates whether it flows to contents of `node`. + * `read` indicates whether it is contents of `p` that can flow to `node`. */ pragma[nomagic] - private predicate parameterValueFlowCand( - ParameterNode p, Node node, boolean read, boolean stored - ) { + private predicate parameterValueFlowCand(ParameterNode p, Node node, boolean read) { p = node and - read = false and - stored = false + read = false or // local flow exists(Node mid | - parameterValueFlowCand(p, mid, read, stored) and + parameterValueFlowCand(p, mid, read) and simpleLocalFlowStep(mid, node) ) or // read - exists(Node mid, boolean readMid, boolean storedMid | - parameterValueFlowCand(p, mid, readMid, storedMid) and - readStep(mid, _, node) and - stored = false - | - // value neither read nor stored prior to read - readMid = false and - storedMid = false and - read = true - or - // value (possibly read and then) stored prior to read (same content) - read = readMid and - storedMid = true - ) - or - // store exists(Node mid | - parameterValueFlowCand(p, mid, read, false) and - storeStep(mid, _, node) and - stored = true + parameterValueFlowCand(p, mid, false) and + readStep(mid, _, node) and + read = true ) or - // flow through: no prior read or store + // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArgCand(p, arg, false, false) and - argumentValueFlowsThroughCand(arg, node, read, stored) + parameterValueFlowArgCand(p, arg, false) and + argumentValueFlowsThroughCand(arg, node, read) ) or - // flow through: no read or store inside method + // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArgCand(p, arg, read, stored) and - argumentValueFlowsThroughCand(arg, node, false, false) - ) - or - // flow through: possible prior read and prior store with compatible - // flow-through method - exists(ArgumentNode arg, boolean mid | - parameterValueFlowArgCand(p, arg, read, mid) and - argumentValueFlowsThroughCand(arg, node, mid, stored) + parameterValueFlowArgCand(p, arg, read) and + argumentValueFlowsThroughCand(arg, node, false) ) } pragma[nomagic] - private predicate parameterValueFlowArgCand( - ParameterNode p, ArgumentNode arg, boolean read, boolean stored - ) { - parameterValueFlowCand(p, arg, read, stored) + private predicate parameterValueFlowArgCand(ParameterNode p, ArgumentNode arg, boolean read) { + parameterValueFlowCand(p, arg, read) } pragma[nomagic] predicate parameterValueFlowsToPreUpdateCand(ParameterNode p, PostUpdateNode n) { - parameterValueFlowCand(p, n.getPreUpdateNode(), false, false) - } - - pragma[nomagic] - private predicate parameterValueFlowsToPostUpdateCand( - ParameterNode p, PostUpdateNode n, boolean read - ) { - parameterValueFlowCand(p, n, read, true) + parameterValueFlowCand(p, n.getPreUpdateNode(), false) } /** @@ -125,33 +106,21 @@ private module Cached { * into account. * * `read` indicates whether it is contents of `p` that can flow to the return - * node, and `stored` indicates whether it flows to contents of the return * node. */ - predicate parameterValueFlowReturnCand( - ParameterNode p, ReturnKindExt kind, boolean read, boolean stored - ) { + predicate parameterValueFlowReturnCand(ParameterNode p, ReturnKind kind, boolean read) { exists(ReturnNode ret | - parameterValueFlowCand(p, ret, read, stored) and - kind = TValueReturn(ret.getKind()) - ) - or - exists(ParameterNode p2, int pos2, PostUpdateNode n | - parameterValueFlowsToPostUpdateCand(p, n, read) and - parameterValueFlowsToPreUpdateCand(p2, n) and - p2.isParameterOf(_, pos2) and - kind = TParamUpdate(pos2) and - p != p2 and - stored = true + parameterValueFlowCand(p, ret, read) and + kind = ret.getKind() ) } pragma[nomagic] private predicate argumentValueFlowsThroughCand0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, boolean read, boolean stored + DataFlowCall call, ArgumentNode arg, ReturnKind kind, boolean read ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturnCand(param, kind, read, stored) + parameterValueFlowReturnCand(param, kind, read) ) } @@ -159,22 +128,19 @@ private module Cached { * Holds if `arg` flows to `out` through a call using only value-preserving steps, * not taking call contexts into account. * - * `read` indicates whether it is contents of `arg` that can flow to `out`, and - * `stored` indicates whether it flows to contents of `out`. + * `read` indicates whether it is contents of `arg` that can flow to `out`. */ - predicate argumentValueFlowsThroughCand( - ArgumentNode arg, Node out, boolean read, boolean stored - ) { - exists(DataFlowCall call, ReturnKindExt kind | - argumentValueFlowsThroughCand0(call, arg, kind, read, stored) and - out = kind.getAnOutNode(call) + predicate argumentValueFlowsThroughCand(ArgumentNode arg, Node out, boolean read) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThroughCand0(call, arg, kind, read) and + out = getAnOutNode(call, kind) ) } predicate cand(ParameterNode p, Node n) { - parameterValueFlowCand(p, n, _, _) and + parameterValueFlowCand(p, n, _) and ( - parameterValueFlowReturnCand(p, _, _, _) + parameterValueFlowReturnCand(p, _, _) or parameterValueFlowsToPreUpdateCand(p, _) ) @@ -187,7 +153,6 @@ private module Cached { ( n instanceof ParameterNode or n instanceof OutNode or - n instanceof PostUpdateNode or readStep(_, _, n) or n instanceof CastNode ) @@ -200,10 +165,6 @@ private module Cached { or n instanceof ReturnNode or - Cand::parameterValueFlowsToPreUpdateCand(_, n) - or - storeStep(n, _, _) - or readStep(n, _, _) or n instanceof CastNode @@ -237,230 +198,140 @@ private module Cached { /** * The final flow-through calculation: * - * - Input/output access paths are abstracted with a `ContentOption` parameter + * - Input access paths are abstracted with a `ContentOption` parameter * that represents the head of the access path. `TContentNone()` means that * the access path is unrestricted. * - Types are checked using the `compatibleTypes()` relation. */ - cached private module Final { /** * Holds if `p` can flow to `node` in the same callable using only * value-preserving steps, not taking call contexts into account. * * `contentIn` describes the content of `p` that can flow to `node` - * (if any), and `contentOut` describes the content of `node` that - * it flows to (if any). + * (if any). */ - private predicate parameterValueFlow( - ParameterNode p, Node node, ContentOption contentIn, ContentOption contentOut - ) { - parameterValueFlow0(p, node, contentIn, contentOut) and + predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) { + parameterValueFlow0(p, node, contentIn) and if node instanceof CastingNode then // normal flow through contentIn = TContentNone() and - contentOut = TContentNone() and compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) or // getter exists(Content fIn | contentIn.getContent() = fIn and - contentOut = TContentNone() and compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node)) ) - or - // (getter+)setter - exists(Content fOut | - contentOut.getContent() = fOut and - compatibleTypes(fOut.getContainerType(), getErasedNodeTypeBound(node)) - ) else any() } pragma[nomagic] - private predicate parameterValueFlow0( - ParameterNode p, Node node, ContentOption contentIn, ContentOption contentOut - ) { + private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() and - contentOut = TContentNone() + contentIn = TContentNone() or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn, contentOut) and + parameterValueFlow(p, mid, contentIn) and LocalFlowBigStep::localFlowBigStep(mid, node) ) or // read - exists(Node mid, Content f, ContentOption contentInMid, ContentOption contentOutMid | - parameterValueFlow(p, mid, contentInMid, contentOutMid) and - readStep(mid, f, node) - | - // value neither read nor stored prior to read - contentInMid = TContentNone() and - contentOutMid = TContentNone() and - contentIn.getContent() = f and - contentOut = TContentNone() and - Cand::parameterValueFlowReturnCand(p, _, true, _) and - compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) - or - // value (possibly read and then) stored prior to read (same content) - contentIn = contentInMid and - contentOutMid.getContent() = f and - contentOut = TContentNone() - ) - or - // store exists(Node mid, Content f | - parameterValueFlow(p, mid, contentIn, TContentNone()) and - storeStep(mid, f, node) and - contentOut.getContent() = f - | - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(p), f.getType()) - or - compatibleTypes(contentIn.getContent().getType(), f.getType()) + parameterValueFlow(p, mid, TContentNone()) and + readStep(mid, f, node) and + contentIn.getContent() = f and + Cand::parameterValueFlowReturnCand(p, _, true) and + compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) ) or - // flow through: no prior read or store + // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, TContentNone(), TContentNone()) and - argumentValueFlowsThrough(_, arg, contentIn, contentOut, node) + parameterValueFlowArg(p, arg, TContentNone()) and + argumentValueFlowsThrough(arg, contentIn, node) ) or - // flow through: no read or store inside method + // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, contentIn, contentOut) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) - ) - or - // flow through: possible prior read and prior store with compatible - // flow-through method - exists(ArgumentNode arg, ContentOption contentMid | - parameterValueFlowArg(p, arg, contentIn, contentMid) and - argumentValueFlowsThrough(_, arg, contentMid, contentOut, node) + parameterValueFlowArg(p, arg, contentIn) and + argumentValueFlowsThrough(arg, TContentNone(), node) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn, ContentOption contentOut + ParameterNode p, ArgumentNode arg, ContentOption contentIn ) { - parameterValueFlow(p, arg, contentIn, contentOut) and - Cand::argumentValueFlowsThroughCand(arg, _, _, _) + parameterValueFlow(p, arg, contentIn) and + Cand::argumentValueFlowsThroughCand(arg, _, _) } pragma[nomagic] private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, ContentOption contentIn, - ContentOption contentOut + DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, _, kind, contentIn, contentOut) + parameterValueFlowReturn(param, kind, contentIn) ) } /** - * Holds if `arg` flows to `out` through `call` using only value-preserving steps, + * Holds if `arg` flows to `out` through a call using only value-preserving steps, * not taking call contexts into account. * - * `contentIn` describes the content of `arg` that can flow to `out` (if any), and - * `contentOut` describes the content of `out` that it flows to (if any). + * `contentIn` describes the content of `arg` that can flow to `out` (if any). */ - cached - predicate argumentValueFlowsThrough( - DataFlowCall call, ArgumentNode arg, ContentOption contentIn, ContentOption contentOut, - Node out - ) { - exists(ReturnKindExt kind | - argumentValueFlowsThrough0(call, arg, kind, contentIn, contentOut) and - out = kind.getAnOutNode(call) + pragma[nomagic] + predicate argumentValueFlowsThrough(ArgumentNode arg, ContentOption contentIn, Node out) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThrough0(call, arg, kind, contentIn) and + out = getAnOutNode(call, kind) | // normal flow through contentIn = TContentNone() and - contentOut = TContentNone() and compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) or // getter exists(Content fIn | contentIn.getContent() = fIn and - contentOut = TContentNone() and compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out)) ) - or - // setter - exists(Content fOut | - contentIn = TContentNone() and - contentOut.getContent() = fOut and - compatibleTypes(getErasedNodeTypeBound(arg), fOut.getType()) and - compatibleTypes(fOut.getContainerType(), getErasedNodeTypeBound(out)) - ) - or - // getter+setter - exists(Content fIn, Content fOut | - contentIn.getContent() = fIn and - contentOut.getContent() = fOut and - compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and - compatibleTypes(fOut.getContainerType(), getErasedNodeTypeBound(out)) - ) ) } - /** - * Holds if `p` can flow to the pre-update node associated with post-update - * node `n`, in the same callable, using only value-preserving steps. - */ - cached - predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone(), TContentNone()) - } - - pragma[nomagic] - private predicate parameterValueFlowsToPostUpdate( - ParameterNode p, PostUpdateNode n, ContentOption contentIn, ContentOption contentOut - ) { - parameterValueFlow(p, n, contentIn, contentOut) and - contentOut.hasContent() - } - /** * Holds if `p` can flow to a return node of kind `kind` in the same * callable using only value-preserving steps. * * `contentIn` describes the content of `p` that can flow to the return - * node (if any), and `contentOut` describes the content of the return - * node that it flows to (if any). + * node (if any). */ - cached - predicate parameterValueFlowReturn( - ParameterNode p, Node ret, ReturnKindExt kind, ContentOption contentIn, - ContentOption contentOut + private predicate parameterValueFlowReturn( + ParameterNode p, ReturnKind kind, ContentOption contentIn ) { - ret = - any(ReturnNode n | - parameterValueFlow(p, n, contentIn, contentOut) and - kind = TValueReturn(n.getKind()) - ) - or - ret = - any(PostUpdateNode n | - exists(ParameterNode p2, int pos2 | - parameterValueFlowsToPostUpdate(p, n, contentIn, contentOut) and - parameterValueFlowsToPreUpdate(p2, n) and - p2.isParameterOf(_, pos2) and - kind = TParamUpdate(pos2) and - p != p2 - ) - ) + exists(ReturnNode ret | + parameterValueFlow(p, ret, contentIn) and + kind = ret.getKind() + ) } } import Final } + /** + * Holds if `p` can flow to the pre-update node associated with post-update + * node `n`, in the same callable, using only value-preserving steps. + */ + cached + predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { + parameterValueFlow(p, n.getPreUpdateNode(), TContentNone()) + } + /** * Holds if data can flow from `node1` to `node2` via a direct assignment to * `f`. @@ -469,14 +340,14 @@ private module Cached { * been stored into, in order to handle cases like `x.f1.f2 = y`. */ cached - predicate storeDirect(Node node1, Content f, Node node2) { + predicate store(Node node1, Content f, Node node2) { storeStep(node1, f, node2) and readStep(_, f, _) or exists(Node n1, Node n2 | n1 = node1.(PostUpdateNode).getPreUpdateNode() and n2 = node2.(PostUpdateNode).getPreUpdateNode() | - argumentValueFlowsThrough(_, n2, TContentSome(f), TContentNone(), n1) + argumentValueFlowsThrough(n2, TContentSome(f), n1) or readStep(n2, f, n1) ) @@ -520,6 +391,21 @@ private module Cached { newtype TReturnKindExt = TValueReturn(ReturnKind kind) or TParamUpdate(int pos) { exists(ParameterNode p | p.isParameterOf(_, pos)) } + + cached + newtype TBooleanOption = + TBooleanNone() or + TBooleanSome(boolean b) { b = true or b = false } + + cached + newtype TAccessPathFront = + TFrontNil(DataFlowType t) or + TFrontHead(Content f) + + cached + newtype TAccessPathFrontOption = + TAccessPathFrontNone() or + TAccessPathFrontSome(AccessPathFront apf) } /** @@ -538,7 +424,7 @@ newtype TContentOption = TContentNone() or TContentSome(Content f) -class ContentOption extends TContentOption { +private class ContentOption extends TContentOption { Content getContent() { this = TContentSome(result) } predicate hasContent() { exists(this.getContent()) } @@ -779,77 +665,58 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { result = viableCallable(call) and cc instanceof CallContextReturn } -newtype TSummary = - TSummaryVal() or - TSummaryTaint() or - TSummaryReadVal(Content f) or - TSummaryReadTaint(Content f) or - TSummaryTaintStore(Content f) - -/** - * A summary of flow through a callable. This can either be value-preserving - * if no additional steps are used, taint-flow if at least one additional step - * is used, or any one of those combined with a store or a read. Summaries - * recorded at a return node are restricted to include at least one additional - * step, as the value-based summaries are calculated independent of the - * configuration. - */ -class Summary extends TSummary { - string toString() { - result = "Val" and this = TSummaryVal() - or - result = "Taint" and this = TSummaryTaint() - or - exists(Content f | - result = "ReadVal " + f.toString() and this = TSummaryReadVal(f) - or - result = "ReadTaint " + f.toString() and this = TSummaryReadTaint(f) - or - result = "TaintStore " + f.toString() and this = TSummaryTaintStore(f) - ) - } - - /** Gets the summary that results from extending this with an additional step. */ - Summary additionalStep() { - this = TSummaryVal() and result = TSummaryTaint() - or - this = TSummaryTaint() and result = TSummaryTaint() - or - exists(Content f | this = TSummaryReadVal(f) and result = TSummaryReadTaint(f)) - or - exists(Content f | this = TSummaryReadTaint(f) and result = TSummaryReadTaint(f)) - } - - /** Gets the summary that results from extending this with a read. */ - Summary readStep(Content f) { this = TSummaryVal() and result = TSummaryReadVal(f) } - - /** Gets the summary that results from extending this with a store. */ - Summary storeStep(Content f) { this = TSummaryTaint() and result = TSummaryTaintStore(f) } - - /** Gets the summary that results from extending this with `step`. */ - bindingset[this, step] - Summary compose(Summary step) { - this = TSummaryVal() and result = step - or - this = TSummaryTaint() and - (step = TSummaryTaint() or step = TSummaryTaintStore(_)) and - result = step - or - exists(Content f | - this = TSummaryReadVal(f) and step = TSummaryTaint() and result = TSummaryReadTaint(f) - ) - or - this = TSummaryReadTaint(_) and step = TSummaryTaint() and result = this - } - - /** Holds if this summary does not include any taint steps. */ - predicate isPartial() { - this = TSummaryVal() or - this = TSummaryReadVal(_) - } -} - pragma[noinline] DataFlowType getErasedNodeTypeBound(Node n) { result = getErasedRepr(n.getTypeBound()) } -predicate readDirect = readStep/3; +predicate read = readStep/3; + +/** An optional Boolean value. */ +class BooleanOption extends TBooleanOption { + string toString() { + this = TBooleanNone() and result = "" + or + this = TBooleanSome(any(boolean b | result = b.toString())) + } +} + +/** + * The front of an access path. This is either a head or a nil. + */ +abstract class AccessPathFront extends TAccessPathFront { + abstract string toString(); + + abstract DataFlowType getType(); + + abstract boolean toBoolNonEmpty(); + + predicate headUsesContent(Content f) { this = TFrontHead(f) } +} + +class AccessPathFrontNil extends AccessPathFront, TFrontNil { + override string toString() { + exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) + } + + override DataFlowType getType() { this = TFrontNil(result) } + + override boolean toBoolNonEmpty() { result = false } +} + +class AccessPathFrontHead extends AccessPathFront, TFrontHead { + override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } + + override DataFlowType getType() { + exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) + } + + override boolean toBoolNonEmpty() { result = true } +} + +/** An optional access path front. */ +class AccessPathFrontOption extends TAccessPathFrontOption { + string toString() { + this = TAccessPathFrontNone() and result = "" + or + this = TAccessPathFrontSome(any(AccessPathFront apf | result = apf.toString())) + } +} From 1b6e978a62de7a70c5543871b8b980506615fa0e Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 18 Mar 2020 20:23:14 +0100 Subject: [PATCH 0181/1298] Data flow: Sync files --- .../cpp/dataflow/internal/DataFlowImpl.qll | 1986 ++++++++--------- .../cpp/dataflow/internal/DataFlowImpl2.qll | 1986 ++++++++--------- .../cpp/dataflow/internal/DataFlowImpl3.qll | 1986 ++++++++--------- .../cpp/dataflow/internal/DataFlowImpl4.qll | 1986 ++++++++--------- .../dataflow/internal/DataFlowImplCommon.qll | 459 ++-- .../dataflow/internal/DataFlowImplLocal.qll | 1986 ++++++++--------- .../cpp/ir/dataflow/internal/DataFlowImpl.qll | 1986 ++++++++--------- .../ir/dataflow/internal/DataFlowImpl2.qll | 1986 ++++++++--------- .../ir/dataflow/internal/DataFlowImpl3.qll | 1986 ++++++++--------- .../ir/dataflow/internal/DataFlowImpl4.qll | 1986 ++++++++--------- .../dataflow/internal/DataFlowImplCommon.qll | 459 ++-- .../dataflow/internal/DataFlowImpl2.qll | 1986 ++++++++--------- .../dataflow/internal/DataFlowImpl3.qll | 1986 ++++++++--------- .../dataflow/internal/DataFlowImpl4.qll | 1986 ++++++++--------- .../dataflow/internal/DataFlowImpl5.qll | 1986 ++++++++--------- .../java/dataflow/internal/DataFlowImpl.qll | 1986 ++++++++--------- .../java/dataflow/internal/DataFlowImpl2.qll | 1986 ++++++++--------- .../java/dataflow/internal/DataFlowImpl3.qll | 1986 ++++++++--------- .../java/dataflow/internal/DataFlowImpl4.qll | 1986 ++++++++--------- .../java/dataflow/internal/DataFlowImpl5.qll | 1986 ++++++++--------- .../dataflow/internal/DataFlowImplCommon.qll | 459 ++-- 21 files changed, 17769 insertions(+), 19356 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..7a04c1f2a75 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -251,15 +251,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +289,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +368,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +379,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +506,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +543,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +557,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) + read(n1, f, n2) } pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) } -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) } pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and - nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) - ) -} - -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) -} - -pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) -} - -/** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +647,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,117 +659,126 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + store(mid, f, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, config) and + exists(Node mid, Content f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, unbind(config)) and + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,7 +1054,7 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or @@ -1292,7 +1062,7 @@ private module LocalFlowBigStep { node instanceof ParameterNode or node instanceof OutNode or node instanceof PostUpdateNode or - readDirect(_, _, node) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1072,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1086,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1109,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,307 +1146,365 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(config)) and +private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(node1, f, node2, config) and +private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) and nodeCand2(node1, config) and - nodeCand2(node2, _, true, unbind(config)) and - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(f, unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) + ) + or + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +pragma[nomagic] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) + ) +} + +/** + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. + */ +pragma[nomagic] +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and + toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) + ) + or + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + else returnApf = TAccessPathFrontNone() } pragma[nomagic] private predicate flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, + Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, apf0, config) and +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, apf, config) + ) +} + +pragma[nomagic] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +private newtype TAccessPathOption = + TAccessPathNone() or + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} + /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) -} - -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true ) } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) + ) +} + +/** + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. + */ +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + or + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and + ap instanceof AccessPathNil + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and + toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + ) + or + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() +} + +pragma[nomagic] +private predicate storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, f, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, ap0, unbind(config)) } pragma[nomagic] private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2050,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2303,7 +2240,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2255,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2347,7 +2284,7 @@ private predicate pathIntoLocalStep( pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2297,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2336,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2352,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2376,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2451,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2492,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2854,7 +2788,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..7a04c1f2a75 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -251,15 +251,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +289,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +368,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +379,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +506,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +543,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +557,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) + read(n1, f, n2) } pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) } -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) } pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and - nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) - ) -} - -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) -} - -pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) -} - -/** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +647,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,117 +659,126 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + store(mid, f, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, config) and + exists(Node mid, Content f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, unbind(config)) and + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,7 +1054,7 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or @@ -1292,7 +1062,7 @@ private module LocalFlowBigStep { node instanceof ParameterNode or node instanceof OutNode or node instanceof PostUpdateNode or - readDirect(_, _, node) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1072,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1086,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1109,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,307 +1146,365 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(config)) and +private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(node1, f, node2, config) and +private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) and nodeCand2(node1, config) and - nodeCand2(node2, _, true, unbind(config)) and - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(f, unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) + ) + or + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +pragma[nomagic] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) + ) +} + +/** + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. + */ +pragma[nomagic] +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and + toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) + ) + or + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + else returnApf = TAccessPathFrontNone() } pragma[nomagic] private predicate flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, + Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, apf0, config) and +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, apf, config) + ) +} + +pragma[nomagic] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +private newtype TAccessPathOption = + TAccessPathNone() or + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} + /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) -} - -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true ) } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) + ) +} + +/** + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. + */ +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + or + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and + ap instanceof AccessPathNil + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and + toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + ) + or + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() +} + +pragma[nomagic] +private predicate storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, f, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, ap0, unbind(config)) } pragma[nomagic] private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2050,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2303,7 +2240,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2255,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2347,7 +2284,7 @@ private predicate pathIntoLocalStep( pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2297,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2336,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2352,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2376,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2451,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2492,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2854,7 +2788,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..7a04c1f2a75 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -251,15 +251,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +289,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +368,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +379,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +506,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +543,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +557,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) + read(n1, f, n2) } pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) } -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) } pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and - nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) - ) -} - -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) -} - -pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) -} - -/** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +647,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,117 +659,126 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + store(mid, f, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, config) and + exists(Node mid, Content f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, unbind(config)) and + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,7 +1054,7 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or @@ -1292,7 +1062,7 @@ private module LocalFlowBigStep { node instanceof ParameterNode or node instanceof OutNode or node instanceof PostUpdateNode or - readDirect(_, _, node) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1072,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1086,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1109,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,307 +1146,365 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(config)) and +private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(node1, f, node2, config) and +private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) and nodeCand2(node1, config) and - nodeCand2(node2, _, true, unbind(config)) and - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(f, unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) + ) + or + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +pragma[nomagic] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) + ) +} + +/** + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. + */ +pragma[nomagic] +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and + toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) + ) + or + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + else returnApf = TAccessPathFrontNone() } pragma[nomagic] private predicate flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, + Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, apf0, config) and +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, apf, config) + ) +} + +pragma[nomagic] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +private newtype TAccessPathOption = + TAccessPathNone() or + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} + /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) -} - -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true ) } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) + ) +} + +/** + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. + */ +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + or + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and + ap instanceof AccessPathNil + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and + toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + ) + or + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() +} + +pragma[nomagic] +private predicate storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, f, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, ap0, unbind(config)) } pragma[nomagic] private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2050,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2303,7 +2240,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2255,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2347,7 +2284,7 @@ private predicate pathIntoLocalStep( pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2297,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2336,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2352,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2376,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2451,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2492,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2854,7 +2788,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..7a04c1f2a75 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -251,15 +251,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +289,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +368,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +379,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +506,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +543,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +557,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) + read(n1, f, n2) } pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) } -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) } pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and - nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) - ) -} - -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) -} - -pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) -} - -/** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +647,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,117 +659,126 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + store(mid, f, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, config) and + exists(Node mid, Content f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, unbind(config)) and + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,7 +1054,7 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or @@ -1292,7 +1062,7 @@ private module LocalFlowBigStep { node instanceof ParameterNode or node instanceof OutNode or node instanceof PostUpdateNode or - readDirect(_, _, node) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1072,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1086,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1109,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,307 +1146,365 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(config)) and +private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(node1, f, node2, config) and +private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) and nodeCand2(node1, config) and - nodeCand2(node2, _, true, unbind(config)) and - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(f, unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) + ) + or + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +pragma[nomagic] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) + ) +} + +/** + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. + */ +pragma[nomagic] +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and + toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) + ) + or + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + else returnApf = TAccessPathFrontNone() } pragma[nomagic] private predicate flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, + Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, apf0, config) and +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, apf, config) + ) +} + +pragma[nomagic] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +private newtype TAccessPathOption = + TAccessPathNone() or + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} + /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) -} - -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true ) } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) + ) +} + +/** + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. + */ +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + or + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and + ap instanceof AccessPathNil + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and + toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + ) + or + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() +} + +pragma[nomagic] +private predicate storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, f, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, ap0, unbind(config)) } pragma[nomagic] private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2050,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2303,7 +2240,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2255,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2347,7 +2284,7 @@ private predicate pathIntoLocalStep( pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2297,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2336,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2352,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2376,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2451,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2492,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2854,7 +2788,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll index 783ac641e6e..b241a574c97 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -26,13 +26,30 @@ private module Cached { ) } - /** Provides predicates for calculating flow-through summaries. */ + pragma[nomagic] + private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { + viableCallable(call) = result.getCallable() and + kind = result.getKind() + } + + /** + * Holds if a value at return position `pos` can be returned to `out` via `call`, + * taking virtual dispatch into account. + */ cached + predicate viableReturnPosOut(DataFlowCall call, ReturnPosition pos, Node out) { + exists(ReturnKindExt kind | + pos = viableReturnPos(call, kind) and + out = kind.getAnOutNode(call) + ) + } + + /** Provides predicates for calculating flow-through summaries. */ private module FlowThrough { /** * The first flow-through approximation: * - * - Input/output access paths are abstracted with a Boolean parameter + * - Input access paths are abstracted with a Boolean parameter * that indicates (non-)emptiness. */ private module Cand { @@ -40,83 +57,47 @@ private module Cached { * Holds if `p` can flow to `node` in the same callable using only * value-preserving steps. * - * `read` indicates whether it is contents of `p` that can flow to `node`, - * and `stored` indicates whether it flows to contents of `node`. + * `read` indicates whether it is contents of `p` that can flow to `node`. */ pragma[nomagic] - private predicate parameterValueFlowCand( - ParameterNode p, Node node, boolean read, boolean stored - ) { + private predicate parameterValueFlowCand(ParameterNode p, Node node, boolean read) { p = node and - read = false and - stored = false + read = false or // local flow exists(Node mid | - parameterValueFlowCand(p, mid, read, stored) and + parameterValueFlowCand(p, mid, read) and simpleLocalFlowStep(mid, node) ) or // read - exists(Node mid, boolean readMid, boolean storedMid | - parameterValueFlowCand(p, mid, readMid, storedMid) and - readStep(mid, _, node) and - stored = false - | - // value neither read nor stored prior to read - readMid = false and - storedMid = false and - read = true - or - // value (possibly read and then) stored prior to read (same content) - read = readMid and - storedMid = true - ) - or - // store exists(Node mid | - parameterValueFlowCand(p, mid, read, false) and - storeStep(mid, _, node) and - stored = true + parameterValueFlowCand(p, mid, false) and + readStep(mid, _, node) and + read = true ) or - // flow through: no prior read or store + // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArgCand(p, arg, false, false) and - argumentValueFlowsThroughCand(arg, node, read, stored) + parameterValueFlowArgCand(p, arg, false) and + argumentValueFlowsThroughCand(arg, node, read) ) or - // flow through: no read or store inside method + // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArgCand(p, arg, read, stored) and - argumentValueFlowsThroughCand(arg, node, false, false) - ) - or - // flow through: possible prior read and prior store with compatible - // flow-through method - exists(ArgumentNode arg, boolean mid | - parameterValueFlowArgCand(p, arg, read, mid) and - argumentValueFlowsThroughCand(arg, node, mid, stored) + parameterValueFlowArgCand(p, arg, read) and + argumentValueFlowsThroughCand(arg, node, false) ) } pragma[nomagic] - private predicate parameterValueFlowArgCand( - ParameterNode p, ArgumentNode arg, boolean read, boolean stored - ) { - parameterValueFlowCand(p, arg, read, stored) + private predicate parameterValueFlowArgCand(ParameterNode p, ArgumentNode arg, boolean read) { + parameterValueFlowCand(p, arg, read) } pragma[nomagic] predicate parameterValueFlowsToPreUpdateCand(ParameterNode p, PostUpdateNode n) { - parameterValueFlowCand(p, n.getPreUpdateNode(), false, false) - } - - pragma[nomagic] - private predicate parameterValueFlowsToPostUpdateCand( - ParameterNode p, PostUpdateNode n, boolean read - ) { - parameterValueFlowCand(p, n, read, true) + parameterValueFlowCand(p, n.getPreUpdateNode(), false) } /** @@ -125,33 +106,21 @@ private module Cached { * into account. * * `read` indicates whether it is contents of `p` that can flow to the return - * node, and `stored` indicates whether it flows to contents of the return * node. */ - predicate parameterValueFlowReturnCand( - ParameterNode p, ReturnKindExt kind, boolean read, boolean stored - ) { + predicate parameterValueFlowReturnCand(ParameterNode p, ReturnKind kind, boolean read) { exists(ReturnNode ret | - parameterValueFlowCand(p, ret, read, stored) and - kind = TValueReturn(ret.getKind()) - ) - or - exists(ParameterNode p2, int pos2, PostUpdateNode n | - parameterValueFlowsToPostUpdateCand(p, n, read) and - parameterValueFlowsToPreUpdateCand(p2, n) and - p2.isParameterOf(_, pos2) and - kind = TParamUpdate(pos2) and - p != p2 and - stored = true + parameterValueFlowCand(p, ret, read) and + kind = ret.getKind() ) } pragma[nomagic] private predicate argumentValueFlowsThroughCand0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, boolean read, boolean stored + DataFlowCall call, ArgumentNode arg, ReturnKind kind, boolean read ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturnCand(param, kind, read, stored) + parameterValueFlowReturnCand(param, kind, read) ) } @@ -159,22 +128,19 @@ private module Cached { * Holds if `arg` flows to `out` through a call using only value-preserving steps, * not taking call contexts into account. * - * `read` indicates whether it is contents of `arg` that can flow to `out`, and - * `stored` indicates whether it flows to contents of `out`. + * `read` indicates whether it is contents of `arg` that can flow to `out`. */ - predicate argumentValueFlowsThroughCand( - ArgumentNode arg, Node out, boolean read, boolean stored - ) { - exists(DataFlowCall call, ReturnKindExt kind | - argumentValueFlowsThroughCand0(call, arg, kind, read, stored) and - out = kind.getAnOutNode(call) + predicate argumentValueFlowsThroughCand(ArgumentNode arg, Node out, boolean read) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThroughCand0(call, arg, kind, read) and + out = getAnOutNode(call, kind) ) } predicate cand(ParameterNode p, Node n) { - parameterValueFlowCand(p, n, _, _) and + parameterValueFlowCand(p, n, _) and ( - parameterValueFlowReturnCand(p, _, _, _) + parameterValueFlowReturnCand(p, _, _) or parameterValueFlowsToPreUpdateCand(p, _) ) @@ -187,7 +153,6 @@ private module Cached { ( n instanceof ParameterNode or n instanceof OutNode or - n instanceof PostUpdateNode or readStep(_, _, n) or n instanceof CastNode ) @@ -200,10 +165,6 @@ private module Cached { or n instanceof ReturnNode or - Cand::parameterValueFlowsToPreUpdateCand(_, n) - or - storeStep(n, _, _) - or readStep(n, _, _) or n instanceof CastNode @@ -237,230 +198,140 @@ private module Cached { /** * The final flow-through calculation: * - * - Input/output access paths are abstracted with a `ContentOption` parameter + * - Input access paths are abstracted with a `ContentOption` parameter * that represents the head of the access path. `TContentNone()` means that * the access path is unrestricted. * - Types are checked using the `compatibleTypes()` relation. */ - cached private module Final { /** * Holds if `p` can flow to `node` in the same callable using only * value-preserving steps, not taking call contexts into account. * * `contentIn` describes the content of `p` that can flow to `node` - * (if any), and `contentOut` describes the content of `node` that - * it flows to (if any). + * (if any). */ - private predicate parameterValueFlow( - ParameterNode p, Node node, ContentOption contentIn, ContentOption contentOut - ) { - parameterValueFlow0(p, node, contentIn, contentOut) and + predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) { + parameterValueFlow0(p, node, contentIn) and if node instanceof CastingNode then // normal flow through contentIn = TContentNone() and - contentOut = TContentNone() and compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) or // getter exists(Content fIn | contentIn.getContent() = fIn and - contentOut = TContentNone() and compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node)) ) - or - // (getter+)setter - exists(Content fOut | - contentOut.getContent() = fOut and - compatibleTypes(fOut.getContainerType(), getErasedNodeTypeBound(node)) - ) else any() } pragma[nomagic] - private predicate parameterValueFlow0( - ParameterNode p, Node node, ContentOption contentIn, ContentOption contentOut - ) { + private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() and - contentOut = TContentNone() + contentIn = TContentNone() or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn, contentOut) and + parameterValueFlow(p, mid, contentIn) and LocalFlowBigStep::localFlowBigStep(mid, node) ) or // read - exists(Node mid, Content f, ContentOption contentInMid, ContentOption contentOutMid | - parameterValueFlow(p, mid, contentInMid, contentOutMid) and - readStep(mid, f, node) - | - // value neither read nor stored prior to read - contentInMid = TContentNone() and - contentOutMid = TContentNone() and - contentIn.getContent() = f and - contentOut = TContentNone() and - Cand::parameterValueFlowReturnCand(p, _, true, _) and - compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) - or - // value (possibly read and then) stored prior to read (same content) - contentIn = contentInMid and - contentOutMid.getContent() = f and - contentOut = TContentNone() - ) - or - // store exists(Node mid, Content f | - parameterValueFlow(p, mid, contentIn, TContentNone()) and - storeStep(mid, f, node) and - contentOut.getContent() = f - | - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(p), f.getType()) - or - compatibleTypes(contentIn.getContent().getType(), f.getType()) + parameterValueFlow(p, mid, TContentNone()) and + readStep(mid, f, node) and + contentIn.getContent() = f and + Cand::parameterValueFlowReturnCand(p, _, true) and + compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) ) or - // flow through: no prior read or store + // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, TContentNone(), TContentNone()) and - argumentValueFlowsThrough(_, arg, contentIn, contentOut, node) + parameterValueFlowArg(p, arg, TContentNone()) and + argumentValueFlowsThrough(arg, contentIn, node) ) or - // flow through: no read or store inside method + // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, contentIn, contentOut) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) - ) - or - // flow through: possible prior read and prior store with compatible - // flow-through method - exists(ArgumentNode arg, ContentOption contentMid | - parameterValueFlowArg(p, arg, contentIn, contentMid) and - argumentValueFlowsThrough(_, arg, contentMid, contentOut, node) + parameterValueFlowArg(p, arg, contentIn) and + argumentValueFlowsThrough(arg, TContentNone(), node) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn, ContentOption contentOut + ParameterNode p, ArgumentNode arg, ContentOption contentIn ) { - parameterValueFlow(p, arg, contentIn, contentOut) and - Cand::argumentValueFlowsThroughCand(arg, _, _, _) + parameterValueFlow(p, arg, contentIn) and + Cand::argumentValueFlowsThroughCand(arg, _, _) } pragma[nomagic] private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, ContentOption contentIn, - ContentOption contentOut + DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, _, kind, contentIn, contentOut) + parameterValueFlowReturn(param, kind, contentIn) ) } /** - * Holds if `arg` flows to `out` through `call` using only value-preserving steps, + * Holds if `arg` flows to `out` through a call using only value-preserving steps, * not taking call contexts into account. * - * `contentIn` describes the content of `arg` that can flow to `out` (if any), and - * `contentOut` describes the content of `out` that it flows to (if any). + * `contentIn` describes the content of `arg` that can flow to `out` (if any). */ - cached - predicate argumentValueFlowsThrough( - DataFlowCall call, ArgumentNode arg, ContentOption contentIn, ContentOption contentOut, - Node out - ) { - exists(ReturnKindExt kind | - argumentValueFlowsThrough0(call, arg, kind, contentIn, contentOut) and - out = kind.getAnOutNode(call) + pragma[nomagic] + predicate argumentValueFlowsThrough(ArgumentNode arg, ContentOption contentIn, Node out) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThrough0(call, arg, kind, contentIn) and + out = getAnOutNode(call, kind) | // normal flow through contentIn = TContentNone() and - contentOut = TContentNone() and compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) or // getter exists(Content fIn | contentIn.getContent() = fIn and - contentOut = TContentNone() and compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out)) ) - or - // setter - exists(Content fOut | - contentIn = TContentNone() and - contentOut.getContent() = fOut and - compatibleTypes(getErasedNodeTypeBound(arg), fOut.getType()) and - compatibleTypes(fOut.getContainerType(), getErasedNodeTypeBound(out)) - ) - or - // getter+setter - exists(Content fIn, Content fOut | - contentIn.getContent() = fIn and - contentOut.getContent() = fOut and - compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and - compatibleTypes(fOut.getContainerType(), getErasedNodeTypeBound(out)) - ) ) } - /** - * Holds if `p` can flow to the pre-update node associated with post-update - * node `n`, in the same callable, using only value-preserving steps. - */ - cached - predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone(), TContentNone()) - } - - pragma[nomagic] - private predicate parameterValueFlowsToPostUpdate( - ParameterNode p, PostUpdateNode n, ContentOption contentIn, ContentOption contentOut - ) { - parameterValueFlow(p, n, contentIn, contentOut) and - contentOut.hasContent() - } - /** * Holds if `p` can flow to a return node of kind `kind` in the same * callable using only value-preserving steps. * * `contentIn` describes the content of `p` that can flow to the return - * node (if any), and `contentOut` describes the content of the return - * node that it flows to (if any). + * node (if any). */ - cached - predicate parameterValueFlowReturn( - ParameterNode p, Node ret, ReturnKindExt kind, ContentOption contentIn, - ContentOption contentOut + private predicate parameterValueFlowReturn( + ParameterNode p, ReturnKind kind, ContentOption contentIn ) { - ret = - any(ReturnNode n | - parameterValueFlow(p, n, contentIn, contentOut) and - kind = TValueReturn(n.getKind()) - ) - or - ret = - any(PostUpdateNode n | - exists(ParameterNode p2, int pos2 | - parameterValueFlowsToPostUpdate(p, n, contentIn, contentOut) and - parameterValueFlowsToPreUpdate(p2, n) and - p2.isParameterOf(_, pos2) and - kind = TParamUpdate(pos2) and - p != p2 - ) - ) + exists(ReturnNode ret | + parameterValueFlow(p, ret, contentIn) and + kind = ret.getKind() + ) } } import Final } + /** + * Holds if `p` can flow to the pre-update node associated with post-update + * node `n`, in the same callable, using only value-preserving steps. + */ + cached + predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { + parameterValueFlow(p, n.getPreUpdateNode(), TContentNone()) + } + /** * Holds if data can flow from `node1` to `node2` via a direct assignment to * `f`. @@ -469,14 +340,14 @@ private module Cached { * been stored into, in order to handle cases like `x.f1.f2 = y`. */ cached - predicate storeDirect(Node node1, Content f, Node node2) { + predicate store(Node node1, Content f, Node node2) { storeStep(node1, f, node2) and readStep(_, f, _) or exists(Node n1, Node n2 | n1 = node1.(PostUpdateNode).getPreUpdateNode() and n2 = node2.(PostUpdateNode).getPreUpdateNode() | - argumentValueFlowsThrough(_, n2, TContentSome(f), TContentNone(), n1) + argumentValueFlowsThrough(n2, TContentSome(f), n1) or readStep(n2, f, n1) ) @@ -520,6 +391,21 @@ private module Cached { newtype TReturnKindExt = TValueReturn(ReturnKind kind) or TParamUpdate(int pos) { exists(ParameterNode p | p.isParameterOf(_, pos)) } + + cached + newtype TBooleanOption = + TBooleanNone() or + TBooleanSome(boolean b) { b = true or b = false } + + cached + newtype TAccessPathFront = + TFrontNil(DataFlowType t) or + TFrontHead(Content f) + + cached + newtype TAccessPathFrontOption = + TAccessPathFrontNone() or + TAccessPathFrontSome(AccessPathFront apf) } /** @@ -538,7 +424,7 @@ newtype TContentOption = TContentNone() or TContentSome(Content f) -class ContentOption extends TContentOption { +private class ContentOption extends TContentOption { Content getContent() { this = TContentSome(result) } predicate hasContent() { exists(this.getContent()) } @@ -779,77 +665,58 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { result = viableCallable(call) and cc instanceof CallContextReturn } -newtype TSummary = - TSummaryVal() or - TSummaryTaint() or - TSummaryReadVal(Content f) or - TSummaryReadTaint(Content f) or - TSummaryTaintStore(Content f) - -/** - * A summary of flow through a callable. This can either be value-preserving - * if no additional steps are used, taint-flow if at least one additional step - * is used, or any one of those combined with a store or a read. Summaries - * recorded at a return node are restricted to include at least one additional - * step, as the value-based summaries are calculated independent of the - * configuration. - */ -class Summary extends TSummary { - string toString() { - result = "Val" and this = TSummaryVal() - or - result = "Taint" and this = TSummaryTaint() - or - exists(Content f | - result = "ReadVal " + f.toString() and this = TSummaryReadVal(f) - or - result = "ReadTaint " + f.toString() and this = TSummaryReadTaint(f) - or - result = "TaintStore " + f.toString() and this = TSummaryTaintStore(f) - ) - } - - /** Gets the summary that results from extending this with an additional step. */ - Summary additionalStep() { - this = TSummaryVal() and result = TSummaryTaint() - or - this = TSummaryTaint() and result = TSummaryTaint() - or - exists(Content f | this = TSummaryReadVal(f) and result = TSummaryReadTaint(f)) - or - exists(Content f | this = TSummaryReadTaint(f) and result = TSummaryReadTaint(f)) - } - - /** Gets the summary that results from extending this with a read. */ - Summary readStep(Content f) { this = TSummaryVal() and result = TSummaryReadVal(f) } - - /** Gets the summary that results from extending this with a store. */ - Summary storeStep(Content f) { this = TSummaryTaint() and result = TSummaryTaintStore(f) } - - /** Gets the summary that results from extending this with `step`. */ - bindingset[this, step] - Summary compose(Summary step) { - this = TSummaryVal() and result = step - or - this = TSummaryTaint() and - (step = TSummaryTaint() or step = TSummaryTaintStore(_)) and - result = step - or - exists(Content f | - this = TSummaryReadVal(f) and step = TSummaryTaint() and result = TSummaryReadTaint(f) - ) - or - this = TSummaryReadTaint(_) and step = TSummaryTaint() and result = this - } - - /** Holds if this summary does not include any taint steps. */ - predicate isPartial() { - this = TSummaryVal() or - this = TSummaryReadVal(_) - } -} - pragma[noinline] DataFlowType getErasedNodeTypeBound(Node n) { result = getErasedRepr(n.getTypeBound()) } -predicate readDirect = readStep/3; +predicate read = readStep/3; + +/** An optional Boolean value. */ +class BooleanOption extends TBooleanOption { + string toString() { + this = TBooleanNone() and result = "" + or + this = TBooleanSome(any(boolean b | result = b.toString())) + } +} + +/** + * The front of an access path. This is either a head or a nil. + */ +abstract class AccessPathFront extends TAccessPathFront { + abstract string toString(); + + abstract DataFlowType getType(); + + abstract boolean toBoolNonEmpty(); + + predicate headUsesContent(Content f) { this = TFrontHead(f) } +} + +class AccessPathFrontNil extends AccessPathFront, TFrontNil { + override string toString() { + exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) + } + + override DataFlowType getType() { this = TFrontNil(result) } + + override boolean toBoolNonEmpty() { result = false } +} + +class AccessPathFrontHead extends AccessPathFront, TFrontHead { + override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } + + override DataFlowType getType() { + exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) + } + + override boolean toBoolNonEmpty() { result = true } +} + +/** An optional access path front. */ +class AccessPathFrontOption extends TAccessPathFrontOption { + string toString() { + this = TAccessPathFrontNone() and result = "" + or + this = TAccessPathFrontSome(any(AccessPathFront apf | result = apf.toString())) + } +} 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..7a04c1f2a75 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -251,15 +251,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +289,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +368,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +379,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +506,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +543,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +557,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) + read(n1, f, n2) } pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) } -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) } pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and - nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) - ) -} - -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) -} - -pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) -} - -/** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +647,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,117 +659,126 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + store(mid, f, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, config) and + exists(Node mid, Content f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, unbind(config)) and + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,7 +1054,7 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or @@ -1292,7 +1062,7 @@ private module LocalFlowBigStep { node instanceof ParameterNode or node instanceof OutNode or node instanceof PostUpdateNode or - readDirect(_, _, node) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1072,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1086,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1109,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,307 +1146,365 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(config)) and +private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(node1, f, node2, config) and +private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) and nodeCand2(node1, config) and - nodeCand2(node2, _, true, unbind(config)) and - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(f, unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) + ) + or + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +pragma[nomagic] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) + ) +} + +/** + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. + */ +pragma[nomagic] +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and + toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) + ) + or + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + else returnApf = TAccessPathFrontNone() } pragma[nomagic] private predicate flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, + Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, apf0, config) and +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, apf, config) + ) +} + +pragma[nomagic] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +private newtype TAccessPathOption = + TAccessPathNone() or + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} + /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) -} - -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true ) } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) + ) +} + +/** + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. + */ +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + or + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and + ap instanceof AccessPathNil + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and + toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + ) + or + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() +} + +pragma[nomagic] +private predicate storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, f, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, ap0, unbind(config)) } pragma[nomagic] private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2050,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2303,7 +2240,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2255,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2347,7 +2284,7 @@ private predicate pathIntoLocalStep( pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2297,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2336,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2352,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2376,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2451,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2492,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2854,7 +2788,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..7a04c1f2a75 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 @@ -251,15 +251,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +289,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +368,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +379,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +506,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +543,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +557,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) + read(n1, f, n2) } pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) } -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) } pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and - nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) - ) -} - -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) -} - -pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) -} - -/** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +647,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,117 +659,126 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + store(mid, f, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, config) and + exists(Node mid, Content f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, unbind(config)) and + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,7 +1054,7 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or @@ -1292,7 +1062,7 @@ private module LocalFlowBigStep { node instanceof ParameterNode or node instanceof OutNode or node instanceof PostUpdateNode or - readDirect(_, _, node) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1072,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1086,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1109,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,307 +1146,365 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(config)) and +private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(node1, f, node2, config) and +private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) and nodeCand2(node1, config) and - nodeCand2(node2, _, true, unbind(config)) and - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(f, unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) + ) + or + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +pragma[nomagic] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) + ) +} + +/** + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. + */ +pragma[nomagic] +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and + toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) + ) + or + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + else returnApf = TAccessPathFrontNone() } pragma[nomagic] private predicate flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, + Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, apf0, config) and +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, apf, config) + ) +} + +pragma[nomagic] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +private newtype TAccessPathOption = + TAccessPathNone() or + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} + /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) -} - -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true ) } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) + ) +} + +/** + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. + */ +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + or + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and + ap instanceof AccessPathNil + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and + toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + ) + or + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() +} + +pragma[nomagic] +private predicate storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, f, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, ap0, unbind(config)) } pragma[nomagic] private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2050,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2303,7 +2240,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2255,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2347,7 +2284,7 @@ private predicate pathIntoLocalStep( pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2297,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2336,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2352,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2376,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2451,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2492,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2854,7 +2788,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..7a04c1f2a75 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 @@ -251,15 +251,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +289,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +368,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +379,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +506,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +543,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +557,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) + read(n1, f, n2) } pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) } -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) } pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and - nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) - ) -} - -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) -} - -pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) -} - -/** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +647,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,117 +659,126 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + store(mid, f, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, config) and + exists(Node mid, Content f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, unbind(config)) and + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,7 +1054,7 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or @@ -1292,7 +1062,7 @@ private module LocalFlowBigStep { node instanceof ParameterNode or node instanceof OutNode or node instanceof PostUpdateNode or - readDirect(_, _, node) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1072,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1086,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1109,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,307 +1146,365 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(config)) and +private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(node1, f, node2, config) and +private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) and nodeCand2(node1, config) and - nodeCand2(node2, _, true, unbind(config)) and - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(f, unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) + ) + or + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +pragma[nomagic] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) + ) +} + +/** + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. + */ +pragma[nomagic] +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and + toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) + ) + or + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + else returnApf = TAccessPathFrontNone() } pragma[nomagic] private predicate flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, + Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, apf0, config) and +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, apf, config) + ) +} + +pragma[nomagic] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +private newtype TAccessPathOption = + TAccessPathNone() or + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} + /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) -} - -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true ) } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) + ) +} + +/** + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. + */ +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + or + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and + ap instanceof AccessPathNil + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and + toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + ) + or + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() +} + +pragma[nomagic] +private predicate storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, f, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, ap0, unbind(config)) } pragma[nomagic] private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2050,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2303,7 +2240,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2255,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2347,7 +2284,7 @@ private predicate pathIntoLocalStep( pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2297,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2336,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2352,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2376,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2451,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2492,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2854,7 +2788,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..7a04c1f2a75 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 @@ -251,15 +251,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +289,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +368,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +379,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +506,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +543,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +557,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) + read(n1, f, n2) } pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) } -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) } pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and - nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) - ) -} - -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) -} - -pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) -} - -/** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +647,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,117 +659,126 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + store(mid, f, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, config) and + exists(Node mid, Content f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, unbind(config)) and + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,7 +1054,7 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or @@ -1292,7 +1062,7 @@ private module LocalFlowBigStep { node instanceof ParameterNode or node instanceof OutNode or node instanceof PostUpdateNode or - readDirect(_, _, node) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1072,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1086,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1109,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,307 +1146,365 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(config)) and +private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(node1, f, node2, config) and +private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) and nodeCand2(node1, config) and - nodeCand2(node2, _, true, unbind(config)) and - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(f, unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) + ) + or + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +pragma[nomagic] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) + ) +} + +/** + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. + */ +pragma[nomagic] +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and + toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) + ) + or + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + else returnApf = TAccessPathFrontNone() } pragma[nomagic] private predicate flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, + Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, apf0, config) and +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, apf, config) + ) +} + +pragma[nomagic] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +private newtype TAccessPathOption = + TAccessPathNone() or + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} + /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) -} - -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true ) } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) + ) +} + +/** + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. + */ +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + or + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and + ap instanceof AccessPathNil + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and + toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + ) + or + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() +} + +pragma[nomagic] +private predicate storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, f, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, ap0, unbind(config)) } pragma[nomagic] private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2050,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2303,7 +2240,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2255,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2347,7 +2284,7 @@ private predicate pathIntoLocalStep( pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2297,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2336,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2352,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2376,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2451,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2492,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2854,7 +2788,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..7a04c1f2a75 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 @@ -251,15 +251,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +289,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +368,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +379,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +506,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +543,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +557,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) + read(n1, f, n2) } pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) } -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) } pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and - nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) - ) -} - -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) -} - -pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) -} - -/** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +647,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,117 +659,126 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + store(mid, f, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, config) and + exists(Node mid, Content f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, unbind(config)) and + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,7 +1054,7 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or @@ -1292,7 +1062,7 @@ private module LocalFlowBigStep { node instanceof ParameterNode or node instanceof OutNode or node instanceof PostUpdateNode or - readDirect(_, _, node) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1072,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1086,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1109,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,307 +1146,365 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(config)) and +private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(node1, f, node2, config) and +private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) and nodeCand2(node1, config) and - nodeCand2(node2, _, true, unbind(config)) and - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(f, unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) + ) + or + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +pragma[nomagic] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) + ) +} + +/** + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. + */ +pragma[nomagic] +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and + toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) + ) + or + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + else returnApf = TAccessPathFrontNone() } pragma[nomagic] private predicate flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, + Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, apf0, config) and +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, apf, config) + ) +} + +pragma[nomagic] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +private newtype TAccessPathOption = + TAccessPathNone() or + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} + /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) -} - -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true ) } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) + ) +} + +/** + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. + */ +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + or + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and + ap instanceof AccessPathNil + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and + toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + ) + or + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() +} + +pragma[nomagic] +private predicate storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, f, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, ap0, unbind(config)) } pragma[nomagic] private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2050,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2303,7 +2240,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2255,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2347,7 +2284,7 @@ private predicate pathIntoLocalStep( pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2297,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2336,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2352,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2376,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2451,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2492,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2854,7 +2788,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll index 783ac641e6e..b241a574c97 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll @@ -26,13 +26,30 @@ private module Cached { ) } - /** Provides predicates for calculating flow-through summaries. */ + pragma[nomagic] + private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { + viableCallable(call) = result.getCallable() and + kind = result.getKind() + } + + /** + * Holds if a value at return position `pos` can be returned to `out` via `call`, + * taking virtual dispatch into account. + */ cached + predicate viableReturnPosOut(DataFlowCall call, ReturnPosition pos, Node out) { + exists(ReturnKindExt kind | + pos = viableReturnPos(call, kind) and + out = kind.getAnOutNode(call) + ) + } + + /** Provides predicates for calculating flow-through summaries. */ private module FlowThrough { /** * The first flow-through approximation: * - * - Input/output access paths are abstracted with a Boolean parameter + * - Input access paths are abstracted with a Boolean parameter * that indicates (non-)emptiness. */ private module Cand { @@ -40,83 +57,47 @@ private module Cached { * Holds if `p` can flow to `node` in the same callable using only * value-preserving steps. * - * `read` indicates whether it is contents of `p` that can flow to `node`, - * and `stored` indicates whether it flows to contents of `node`. + * `read` indicates whether it is contents of `p` that can flow to `node`. */ pragma[nomagic] - private predicate parameterValueFlowCand( - ParameterNode p, Node node, boolean read, boolean stored - ) { + private predicate parameterValueFlowCand(ParameterNode p, Node node, boolean read) { p = node and - read = false and - stored = false + read = false or // local flow exists(Node mid | - parameterValueFlowCand(p, mid, read, stored) and + parameterValueFlowCand(p, mid, read) and simpleLocalFlowStep(mid, node) ) or // read - exists(Node mid, boolean readMid, boolean storedMid | - parameterValueFlowCand(p, mid, readMid, storedMid) and - readStep(mid, _, node) and - stored = false - | - // value neither read nor stored prior to read - readMid = false and - storedMid = false and - read = true - or - // value (possibly read and then) stored prior to read (same content) - read = readMid and - storedMid = true - ) - or - // store exists(Node mid | - parameterValueFlowCand(p, mid, read, false) and - storeStep(mid, _, node) and - stored = true + parameterValueFlowCand(p, mid, false) and + readStep(mid, _, node) and + read = true ) or - // flow through: no prior read or store + // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArgCand(p, arg, false, false) and - argumentValueFlowsThroughCand(arg, node, read, stored) + parameterValueFlowArgCand(p, arg, false) and + argumentValueFlowsThroughCand(arg, node, read) ) or - // flow through: no read or store inside method + // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArgCand(p, arg, read, stored) and - argumentValueFlowsThroughCand(arg, node, false, false) - ) - or - // flow through: possible prior read and prior store with compatible - // flow-through method - exists(ArgumentNode arg, boolean mid | - parameterValueFlowArgCand(p, arg, read, mid) and - argumentValueFlowsThroughCand(arg, node, mid, stored) + parameterValueFlowArgCand(p, arg, read) and + argumentValueFlowsThroughCand(arg, node, false) ) } pragma[nomagic] - private predicate parameterValueFlowArgCand( - ParameterNode p, ArgumentNode arg, boolean read, boolean stored - ) { - parameterValueFlowCand(p, arg, read, stored) + private predicate parameterValueFlowArgCand(ParameterNode p, ArgumentNode arg, boolean read) { + parameterValueFlowCand(p, arg, read) } pragma[nomagic] predicate parameterValueFlowsToPreUpdateCand(ParameterNode p, PostUpdateNode n) { - parameterValueFlowCand(p, n.getPreUpdateNode(), false, false) - } - - pragma[nomagic] - private predicate parameterValueFlowsToPostUpdateCand( - ParameterNode p, PostUpdateNode n, boolean read - ) { - parameterValueFlowCand(p, n, read, true) + parameterValueFlowCand(p, n.getPreUpdateNode(), false) } /** @@ -125,33 +106,21 @@ private module Cached { * into account. * * `read` indicates whether it is contents of `p` that can flow to the return - * node, and `stored` indicates whether it flows to contents of the return * node. */ - predicate parameterValueFlowReturnCand( - ParameterNode p, ReturnKindExt kind, boolean read, boolean stored - ) { + predicate parameterValueFlowReturnCand(ParameterNode p, ReturnKind kind, boolean read) { exists(ReturnNode ret | - parameterValueFlowCand(p, ret, read, stored) and - kind = TValueReturn(ret.getKind()) - ) - or - exists(ParameterNode p2, int pos2, PostUpdateNode n | - parameterValueFlowsToPostUpdateCand(p, n, read) and - parameterValueFlowsToPreUpdateCand(p2, n) and - p2.isParameterOf(_, pos2) and - kind = TParamUpdate(pos2) and - p != p2 and - stored = true + parameterValueFlowCand(p, ret, read) and + kind = ret.getKind() ) } pragma[nomagic] private predicate argumentValueFlowsThroughCand0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, boolean read, boolean stored + DataFlowCall call, ArgumentNode arg, ReturnKind kind, boolean read ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturnCand(param, kind, read, stored) + parameterValueFlowReturnCand(param, kind, read) ) } @@ -159,22 +128,19 @@ private module Cached { * Holds if `arg` flows to `out` through a call using only value-preserving steps, * not taking call contexts into account. * - * `read` indicates whether it is contents of `arg` that can flow to `out`, and - * `stored` indicates whether it flows to contents of `out`. + * `read` indicates whether it is contents of `arg` that can flow to `out`. */ - predicate argumentValueFlowsThroughCand( - ArgumentNode arg, Node out, boolean read, boolean stored - ) { - exists(DataFlowCall call, ReturnKindExt kind | - argumentValueFlowsThroughCand0(call, arg, kind, read, stored) and - out = kind.getAnOutNode(call) + predicate argumentValueFlowsThroughCand(ArgumentNode arg, Node out, boolean read) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThroughCand0(call, arg, kind, read) and + out = getAnOutNode(call, kind) ) } predicate cand(ParameterNode p, Node n) { - parameterValueFlowCand(p, n, _, _) and + parameterValueFlowCand(p, n, _) and ( - parameterValueFlowReturnCand(p, _, _, _) + parameterValueFlowReturnCand(p, _, _) or parameterValueFlowsToPreUpdateCand(p, _) ) @@ -187,7 +153,6 @@ private module Cached { ( n instanceof ParameterNode or n instanceof OutNode or - n instanceof PostUpdateNode or readStep(_, _, n) or n instanceof CastNode ) @@ -200,10 +165,6 @@ private module Cached { or n instanceof ReturnNode or - Cand::parameterValueFlowsToPreUpdateCand(_, n) - or - storeStep(n, _, _) - or readStep(n, _, _) or n instanceof CastNode @@ -237,230 +198,140 @@ private module Cached { /** * The final flow-through calculation: * - * - Input/output access paths are abstracted with a `ContentOption` parameter + * - Input access paths are abstracted with a `ContentOption` parameter * that represents the head of the access path. `TContentNone()` means that * the access path is unrestricted. * - Types are checked using the `compatibleTypes()` relation. */ - cached private module Final { /** * Holds if `p` can flow to `node` in the same callable using only * value-preserving steps, not taking call contexts into account. * * `contentIn` describes the content of `p` that can flow to `node` - * (if any), and `contentOut` describes the content of `node` that - * it flows to (if any). + * (if any). */ - private predicate parameterValueFlow( - ParameterNode p, Node node, ContentOption contentIn, ContentOption contentOut - ) { - parameterValueFlow0(p, node, contentIn, contentOut) and + predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) { + parameterValueFlow0(p, node, contentIn) and if node instanceof CastingNode then // normal flow through contentIn = TContentNone() and - contentOut = TContentNone() and compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) or // getter exists(Content fIn | contentIn.getContent() = fIn and - contentOut = TContentNone() and compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node)) ) - or - // (getter+)setter - exists(Content fOut | - contentOut.getContent() = fOut and - compatibleTypes(fOut.getContainerType(), getErasedNodeTypeBound(node)) - ) else any() } pragma[nomagic] - private predicate parameterValueFlow0( - ParameterNode p, Node node, ContentOption contentIn, ContentOption contentOut - ) { + private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() and - contentOut = TContentNone() + contentIn = TContentNone() or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn, contentOut) and + parameterValueFlow(p, mid, contentIn) and LocalFlowBigStep::localFlowBigStep(mid, node) ) or // read - exists(Node mid, Content f, ContentOption contentInMid, ContentOption contentOutMid | - parameterValueFlow(p, mid, contentInMid, contentOutMid) and - readStep(mid, f, node) - | - // value neither read nor stored prior to read - contentInMid = TContentNone() and - contentOutMid = TContentNone() and - contentIn.getContent() = f and - contentOut = TContentNone() and - Cand::parameterValueFlowReturnCand(p, _, true, _) and - compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) - or - // value (possibly read and then) stored prior to read (same content) - contentIn = contentInMid and - contentOutMid.getContent() = f and - contentOut = TContentNone() - ) - or - // store exists(Node mid, Content f | - parameterValueFlow(p, mid, contentIn, TContentNone()) and - storeStep(mid, f, node) and - contentOut.getContent() = f - | - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(p), f.getType()) - or - compatibleTypes(contentIn.getContent().getType(), f.getType()) + parameterValueFlow(p, mid, TContentNone()) and + readStep(mid, f, node) and + contentIn.getContent() = f and + Cand::parameterValueFlowReturnCand(p, _, true) and + compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) ) or - // flow through: no prior read or store + // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, TContentNone(), TContentNone()) and - argumentValueFlowsThrough(_, arg, contentIn, contentOut, node) + parameterValueFlowArg(p, arg, TContentNone()) and + argumentValueFlowsThrough(arg, contentIn, node) ) or - // flow through: no read or store inside method + // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, contentIn, contentOut) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) - ) - or - // flow through: possible prior read and prior store with compatible - // flow-through method - exists(ArgumentNode arg, ContentOption contentMid | - parameterValueFlowArg(p, arg, contentIn, contentMid) and - argumentValueFlowsThrough(_, arg, contentMid, contentOut, node) + parameterValueFlowArg(p, arg, contentIn) and + argumentValueFlowsThrough(arg, TContentNone(), node) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn, ContentOption contentOut + ParameterNode p, ArgumentNode arg, ContentOption contentIn ) { - parameterValueFlow(p, arg, contentIn, contentOut) and - Cand::argumentValueFlowsThroughCand(arg, _, _, _) + parameterValueFlow(p, arg, contentIn) and + Cand::argumentValueFlowsThroughCand(arg, _, _) } pragma[nomagic] private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, ContentOption contentIn, - ContentOption contentOut + DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, _, kind, contentIn, contentOut) + parameterValueFlowReturn(param, kind, contentIn) ) } /** - * Holds if `arg` flows to `out` through `call` using only value-preserving steps, + * Holds if `arg` flows to `out` through a call using only value-preserving steps, * not taking call contexts into account. * - * `contentIn` describes the content of `arg` that can flow to `out` (if any), and - * `contentOut` describes the content of `out` that it flows to (if any). + * `contentIn` describes the content of `arg` that can flow to `out` (if any). */ - cached - predicate argumentValueFlowsThrough( - DataFlowCall call, ArgumentNode arg, ContentOption contentIn, ContentOption contentOut, - Node out - ) { - exists(ReturnKindExt kind | - argumentValueFlowsThrough0(call, arg, kind, contentIn, contentOut) and - out = kind.getAnOutNode(call) + pragma[nomagic] + predicate argumentValueFlowsThrough(ArgumentNode arg, ContentOption contentIn, Node out) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThrough0(call, arg, kind, contentIn) and + out = getAnOutNode(call, kind) | // normal flow through contentIn = TContentNone() and - contentOut = TContentNone() and compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) or // getter exists(Content fIn | contentIn.getContent() = fIn and - contentOut = TContentNone() and compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out)) ) - or - // setter - exists(Content fOut | - contentIn = TContentNone() and - contentOut.getContent() = fOut and - compatibleTypes(getErasedNodeTypeBound(arg), fOut.getType()) and - compatibleTypes(fOut.getContainerType(), getErasedNodeTypeBound(out)) - ) - or - // getter+setter - exists(Content fIn, Content fOut | - contentIn.getContent() = fIn and - contentOut.getContent() = fOut and - compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and - compatibleTypes(fOut.getContainerType(), getErasedNodeTypeBound(out)) - ) ) } - /** - * Holds if `p` can flow to the pre-update node associated with post-update - * node `n`, in the same callable, using only value-preserving steps. - */ - cached - predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone(), TContentNone()) - } - - pragma[nomagic] - private predicate parameterValueFlowsToPostUpdate( - ParameterNode p, PostUpdateNode n, ContentOption contentIn, ContentOption contentOut - ) { - parameterValueFlow(p, n, contentIn, contentOut) and - contentOut.hasContent() - } - /** * Holds if `p` can flow to a return node of kind `kind` in the same * callable using only value-preserving steps. * * `contentIn` describes the content of `p` that can flow to the return - * node (if any), and `contentOut` describes the content of the return - * node that it flows to (if any). + * node (if any). */ - cached - predicate parameterValueFlowReturn( - ParameterNode p, Node ret, ReturnKindExt kind, ContentOption contentIn, - ContentOption contentOut + private predicate parameterValueFlowReturn( + ParameterNode p, ReturnKind kind, ContentOption contentIn ) { - ret = - any(ReturnNode n | - parameterValueFlow(p, n, contentIn, contentOut) and - kind = TValueReturn(n.getKind()) - ) - or - ret = - any(PostUpdateNode n | - exists(ParameterNode p2, int pos2 | - parameterValueFlowsToPostUpdate(p, n, contentIn, contentOut) and - parameterValueFlowsToPreUpdate(p2, n) and - p2.isParameterOf(_, pos2) and - kind = TParamUpdate(pos2) and - p != p2 - ) - ) + exists(ReturnNode ret | + parameterValueFlow(p, ret, contentIn) and + kind = ret.getKind() + ) } } import Final } + /** + * Holds if `p` can flow to the pre-update node associated with post-update + * node `n`, in the same callable, using only value-preserving steps. + */ + cached + predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { + parameterValueFlow(p, n.getPreUpdateNode(), TContentNone()) + } + /** * Holds if data can flow from `node1` to `node2` via a direct assignment to * `f`. @@ -469,14 +340,14 @@ private module Cached { * been stored into, in order to handle cases like `x.f1.f2 = y`. */ cached - predicate storeDirect(Node node1, Content f, Node node2) { + predicate store(Node node1, Content f, Node node2) { storeStep(node1, f, node2) and readStep(_, f, _) or exists(Node n1, Node n2 | n1 = node1.(PostUpdateNode).getPreUpdateNode() and n2 = node2.(PostUpdateNode).getPreUpdateNode() | - argumentValueFlowsThrough(_, n2, TContentSome(f), TContentNone(), n1) + argumentValueFlowsThrough(n2, TContentSome(f), n1) or readStep(n2, f, n1) ) @@ -520,6 +391,21 @@ private module Cached { newtype TReturnKindExt = TValueReturn(ReturnKind kind) or TParamUpdate(int pos) { exists(ParameterNode p | p.isParameterOf(_, pos)) } + + cached + newtype TBooleanOption = + TBooleanNone() or + TBooleanSome(boolean b) { b = true or b = false } + + cached + newtype TAccessPathFront = + TFrontNil(DataFlowType t) or + TFrontHead(Content f) + + cached + newtype TAccessPathFrontOption = + TAccessPathFrontNone() or + TAccessPathFrontSome(AccessPathFront apf) } /** @@ -538,7 +424,7 @@ newtype TContentOption = TContentNone() or TContentSome(Content f) -class ContentOption extends TContentOption { +private class ContentOption extends TContentOption { Content getContent() { this = TContentSome(result) } predicate hasContent() { exists(this.getContent()) } @@ -779,77 +665,58 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { result = viableCallable(call) and cc instanceof CallContextReturn } -newtype TSummary = - TSummaryVal() or - TSummaryTaint() or - TSummaryReadVal(Content f) or - TSummaryReadTaint(Content f) or - TSummaryTaintStore(Content f) - -/** - * A summary of flow through a callable. This can either be value-preserving - * if no additional steps are used, taint-flow if at least one additional step - * is used, or any one of those combined with a store or a read. Summaries - * recorded at a return node are restricted to include at least one additional - * step, as the value-based summaries are calculated independent of the - * configuration. - */ -class Summary extends TSummary { - string toString() { - result = "Val" and this = TSummaryVal() - or - result = "Taint" and this = TSummaryTaint() - or - exists(Content f | - result = "ReadVal " + f.toString() and this = TSummaryReadVal(f) - or - result = "ReadTaint " + f.toString() and this = TSummaryReadTaint(f) - or - result = "TaintStore " + f.toString() and this = TSummaryTaintStore(f) - ) - } - - /** Gets the summary that results from extending this with an additional step. */ - Summary additionalStep() { - this = TSummaryVal() and result = TSummaryTaint() - or - this = TSummaryTaint() and result = TSummaryTaint() - or - exists(Content f | this = TSummaryReadVal(f) and result = TSummaryReadTaint(f)) - or - exists(Content f | this = TSummaryReadTaint(f) and result = TSummaryReadTaint(f)) - } - - /** Gets the summary that results from extending this with a read. */ - Summary readStep(Content f) { this = TSummaryVal() and result = TSummaryReadVal(f) } - - /** Gets the summary that results from extending this with a store. */ - Summary storeStep(Content f) { this = TSummaryTaint() and result = TSummaryTaintStore(f) } - - /** Gets the summary that results from extending this with `step`. */ - bindingset[this, step] - Summary compose(Summary step) { - this = TSummaryVal() and result = step - or - this = TSummaryTaint() and - (step = TSummaryTaint() or step = TSummaryTaintStore(_)) and - result = step - or - exists(Content f | - this = TSummaryReadVal(f) and step = TSummaryTaint() and result = TSummaryReadTaint(f) - ) - or - this = TSummaryReadTaint(_) and step = TSummaryTaint() and result = this - } - - /** Holds if this summary does not include any taint steps. */ - predicate isPartial() { - this = TSummaryVal() or - this = TSummaryReadVal(_) - } -} - pragma[noinline] DataFlowType getErasedNodeTypeBound(Node n) { result = getErasedRepr(n.getTypeBound()) } -predicate readDirect = readStep/3; +predicate read = readStep/3; + +/** An optional Boolean value. */ +class BooleanOption extends TBooleanOption { + string toString() { + this = TBooleanNone() and result = "" + or + this = TBooleanSome(any(boolean b | result = b.toString())) + } +} + +/** + * The front of an access path. This is either a head or a nil. + */ +abstract class AccessPathFront extends TAccessPathFront { + abstract string toString(); + + abstract DataFlowType getType(); + + abstract boolean toBoolNonEmpty(); + + predicate headUsesContent(Content f) { this = TFrontHead(f) } +} + +class AccessPathFrontNil extends AccessPathFront, TFrontNil { + override string toString() { + exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) + } + + override DataFlowType getType() { this = TFrontNil(result) } + + override boolean toBoolNonEmpty() { result = false } +} + +class AccessPathFrontHead extends AccessPathFront, TFrontHead { + override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } + + override DataFlowType getType() { + exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) + } + + override boolean toBoolNonEmpty() { result = true } +} + +/** An optional access path front. */ +class AccessPathFrontOption extends TAccessPathFrontOption { + string toString() { + this = TAccessPathFrontNone() and result = "" + or + this = TAccessPathFrontSome(any(AccessPathFront apf | result = apf.toString())) + } +} 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..7a04c1f2a75 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -251,15 +251,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +289,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +368,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +379,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +506,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +543,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +557,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) + read(n1, f, n2) } pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) } -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) } pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and - nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) - ) -} - -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) -} - -pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) -} - -/** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +647,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,117 +659,126 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + store(mid, f, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, config) and + exists(Node mid, Content f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, unbind(config)) and + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,7 +1054,7 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or @@ -1292,7 +1062,7 @@ private module LocalFlowBigStep { node instanceof ParameterNode or node instanceof OutNode or node instanceof PostUpdateNode or - readDirect(_, _, node) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1072,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1086,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1109,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,307 +1146,365 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(config)) and +private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(node1, f, node2, config) and +private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) and nodeCand2(node1, config) and - nodeCand2(node2, _, true, unbind(config)) and - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(f, unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) + ) + or + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +pragma[nomagic] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) + ) +} + +/** + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. + */ +pragma[nomagic] +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and + toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) + ) + or + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + else returnApf = TAccessPathFrontNone() } pragma[nomagic] private predicate flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, + Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, apf0, config) and +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, apf, config) + ) +} + +pragma[nomagic] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +private newtype TAccessPathOption = + TAccessPathNone() or + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} + /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) -} - -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true ) } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) + ) +} + +/** + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. + */ +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + or + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and + ap instanceof AccessPathNil + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and + toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + ) + or + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() +} + +pragma[nomagic] +private predicate storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, f, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, ap0, unbind(config)) } pragma[nomagic] private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2050,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2303,7 +2240,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2255,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2347,7 +2284,7 @@ private predicate pathIntoLocalStep( pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2297,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2336,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2352,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2376,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2451,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2492,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2854,7 +2788,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..7a04c1f2a75 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -251,15 +251,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +289,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +368,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +379,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +506,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +543,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +557,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) + read(n1, f, n2) } pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) } -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) } pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and - nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) - ) -} - -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) -} - -pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) -} - -/** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +647,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,117 +659,126 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + store(mid, f, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, config) and + exists(Node mid, Content f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, unbind(config)) and + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,7 +1054,7 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or @@ -1292,7 +1062,7 @@ private module LocalFlowBigStep { node instanceof ParameterNode or node instanceof OutNode or node instanceof PostUpdateNode or - readDirect(_, _, node) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1072,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1086,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1109,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,307 +1146,365 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(config)) and +private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(node1, f, node2, config) and +private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) and nodeCand2(node1, config) and - nodeCand2(node2, _, true, unbind(config)) and - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(f, unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) + ) + or + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +pragma[nomagic] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) + ) +} + +/** + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. + */ +pragma[nomagic] +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and + toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) + ) + or + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + else returnApf = TAccessPathFrontNone() } pragma[nomagic] private predicate flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, + Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, apf0, config) and +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, apf, config) + ) +} + +pragma[nomagic] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +private newtype TAccessPathOption = + TAccessPathNone() or + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} + /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) -} - -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true ) } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) + ) +} + +/** + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. + */ +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + or + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and + ap instanceof AccessPathNil + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and + toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + ) + or + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() +} + +pragma[nomagic] +private predicate storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, f, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, ap0, unbind(config)) } pragma[nomagic] private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2050,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2303,7 +2240,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2255,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2347,7 +2284,7 @@ private predicate pathIntoLocalStep( pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2297,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2336,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2352,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2376,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2451,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2492,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2854,7 +2788,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..7a04c1f2a75 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -251,15 +251,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +289,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +368,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +379,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +506,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +543,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +557,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) + read(n1, f, n2) } pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) } -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) } pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and - nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) - ) -} - -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) -} - -pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) -} - -/** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +647,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,117 +659,126 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + store(mid, f, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, config) and + exists(Node mid, Content f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, unbind(config)) and + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,7 +1054,7 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or @@ -1292,7 +1062,7 @@ private module LocalFlowBigStep { node instanceof ParameterNode or node instanceof OutNode or node instanceof PostUpdateNode or - readDirect(_, _, node) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1072,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1086,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1109,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,307 +1146,365 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(config)) and +private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(node1, f, node2, config) and +private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) and nodeCand2(node1, config) and - nodeCand2(node2, _, true, unbind(config)) and - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(f, unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) + ) + or + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +pragma[nomagic] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) + ) +} + +/** + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. + */ +pragma[nomagic] +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and + toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) + ) + or + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + else returnApf = TAccessPathFrontNone() } pragma[nomagic] private predicate flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, + Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, apf0, config) and +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, apf, config) + ) +} + +pragma[nomagic] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +private newtype TAccessPathOption = + TAccessPathNone() or + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} + /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) -} - -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true ) } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) + ) +} + +/** + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. + */ +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + or + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and + ap instanceof AccessPathNil + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and + toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + ) + or + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() +} + +pragma[nomagic] +private predicate storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, f, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, ap0, unbind(config)) } pragma[nomagic] private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2050,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2303,7 +2240,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2255,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2347,7 +2284,7 @@ private predicate pathIntoLocalStep( pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2297,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2336,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2352,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2376,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2451,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2492,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2854,7 +2788,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..7a04c1f2a75 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -251,15 +251,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +289,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +368,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +379,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +506,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +543,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +557,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) + read(n1, f, n2) } pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) } -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) } pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and - nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) - ) -} - -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) -} - -pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) -} - -/** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +647,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,117 +659,126 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + store(mid, f, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, config) and + exists(Node mid, Content f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, unbind(config)) and + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,7 +1054,7 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or @@ -1292,7 +1062,7 @@ private module LocalFlowBigStep { node instanceof ParameterNode or node instanceof OutNode or node instanceof PostUpdateNode or - readDirect(_, _, node) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1072,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1086,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1109,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,307 +1146,365 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(config)) and +private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(node1, f, node2, config) and +private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) and nodeCand2(node1, config) and - nodeCand2(node2, _, true, unbind(config)) and - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(f, unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) + ) + or + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +pragma[nomagic] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) + ) +} + +/** + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. + */ +pragma[nomagic] +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and + toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) + ) + or + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + else returnApf = TAccessPathFrontNone() } pragma[nomagic] private predicate flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, + Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, apf0, config) and +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, apf, config) + ) +} + +pragma[nomagic] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +private newtype TAccessPathOption = + TAccessPathNone() or + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} + /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) -} - -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true ) } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) + ) +} + +/** + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. + */ +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + or + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and + ap instanceof AccessPathNil + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and + toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + ) + or + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() +} + +pragma[nomagic] +private predicate storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, f, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, ap0, unbind(config)) } pragma[nomagic] private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2050,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2303,7 +2240,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2255,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2347,7 +2284,7 @@ private predicate pathIntoLocalStep( pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2297,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2336,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2352,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2376,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2451,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2492,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2854,7 +2788,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..7a04c1f2a75 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -251,15 +251,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +289,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +368,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +379,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +506,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +543,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +557,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) + read(n1, f, n2) } pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) } -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) } pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and - nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) - ) -} - -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) -} - -pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) -} - -/** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +647,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,117 +659,126 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + store(mid, f, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, config) and + exists(Node mid, Content f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, unbind(config)) and + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,7 +1054,7 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or @@ -1292,7 +1062,7 @@ private module LocalFlowBigStep { node instanceof ParameterNode or node instanceof OutNode or node instanceof PostUpdateNode or - readDirect(_, _, node) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1072,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1086,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1109,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,307 +1146,365 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(config)) and +private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(node1, f, node2, config) and +private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) and nodeCand2(node1, config) and - nodeCand2(node2, _, true, unbind(config)) and - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(f, unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) + ) + or + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +pragma[nomagic] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) + ) +} + +/** + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. + */ +pragma[nomagic] +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and + toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) + ) + or + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + else returnApf = TAccessPathFrontNone() } pragma[nomagic] private predicate flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, + Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, apf0, config) and +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, apf, config) + ) +} + +pragma[nomagic] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +private newtype TAccessPathOption = + TAccessPathNone() or + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} + /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) -} - -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true ) } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) + ) +} + +/** + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. + */ +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + or + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and + ap instanceof AccessPathNil + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and + toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + ) + or + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() +} + +pragma[nomagic] +private predicate storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, f, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, ap0, unbind(config)) } pragma[nomagic] private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2050,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2303,7 +2240,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2255,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2347,7 +2284,7 @@ private predicate pathIntoLocalStep( pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2297,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2336,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2352,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2376,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2451,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2492,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2854,7 +2788,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..7a04c1f2a75 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -251,15 +251,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +289,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +368,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +379,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +506,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +543,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +557,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) + read(n1, f, n2) } pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) } -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) } pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and - nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) - ) -} - -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) -} - -pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) -} - -/** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +647,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,117 +659,126 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + store(mid, f, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, config) and + exists(Node mid, Content f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, unbind(config)) and + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,7 +1054,7 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or @@ -1292,7 +1062,7 @@ private module LocalFlowBigStep { node instanceof ParameterNode or node instanceof OutNode or node instanceof PostUpdateNode or - readDirect(_, _, node) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1072,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1086,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1109,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,307 +1146,365 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(config)) and +private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(node1, f, node2, config) and +private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) and nodeCand2(node1, config) and - nodeCand2(node2, _, true, unbind(config)) and - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(f, unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) + ) + or + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +pragma[nomagic] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) + ) +} + +/** + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. + */ +pragma[nomagic] +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and + toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) + ) + or + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + else returnApf = TAccessPathFrontNone() } pragma[nomagic] private predicate flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, + Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, apf0, config) and +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, apf, config) + ) +} + +pragma[nomagic] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +private newtype TAccessPathOption = + TAccessPathNone() or + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} + /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) -} - -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true ) } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) + ) +} + +/** + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. + */ +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + or + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and + ap instanceof AccessPathNil + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and + toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + ) + or + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() +} + +pragma[nomagic] +private predicate storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, f, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, ap0, unbind(config)) } pragma[nomagic] private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2050,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2303,7 +2240,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2255,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2347,7 +2284,7 @@ private predicate pathIntoLocalStep( pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2297,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2336,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2352,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2376,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2451,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2492,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2854,7 +2788,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..7a04c1f2a75 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -251,15 +251,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +289,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +368,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +379,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +506,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +543,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +557,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) + read(n1, f, n2) } pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) } -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) } pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and - nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) - ) -} - -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) -} - -pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) -} - -/** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +647,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,117 +659,126 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + store(mid, f, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, config) and + exists(Node mid, Content f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, unbind(config)) and + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,7 +1054,7 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or @@ -1292,7 +1062,7 @@ private module LocalFlowBigStep { node instanceof ParameterNode or node instanceof OutNode or node instanceof PostUpdateNode or - readDirect(_, _, node) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1072,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1086,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1109,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,307 +1146,365 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(config)) and +private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(node1, f, node2, config) and +private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) and nodeCand2(node1, config) and - nodeCand2(node2, _, true, unbind(config)) and - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(f, unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) + ) + or + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +pragma[nomagic] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) + ) +} + +/** + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. + */ +pragma[nomagic] +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and + toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) + ) + or + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + else returnApf = TAccessPathFrontNone() } pragma[nomagic] private predicate flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, + Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, apf0, config) and +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, apf, config) + ) +} + +pragma[nomagic] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +private newtype TAccessPathOption = + TAccessPathNone() or + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} + /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) -} - -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true ) } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) + ) +} + +/** + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. + */ +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + or + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and + ap instanceof AccessPathNil + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and + toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + ) + or + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() +} + +pragma[nomagic] +private predicate storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, f, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, ap0, unbind(config)) } pragma[nomagic] private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2050,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2303,7 +2240,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2255,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2347,7 +2284,7 @@ private predicate pathIntoLocalStep( pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2297,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2336,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2352,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2376,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2451,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2492,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2854,7 +2788,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..7a04c1f2a75 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -251,15 +251,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +289,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +368,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +379,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +506,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +543,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +557,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) + read(n1, f, n2) } pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) } -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) } pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and - nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) - ) -} - -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) -} - -pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) -} - -/** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +647,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,117 +659,126 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + store(mid, f, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, config) and + exists(Node mid, Content f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, unbind(config)) and + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,7 +1054,7 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or @@ -1292,7 +1062,7 @@ private module LocalFlowBigStep { node instanceof ParameterNode or node instanceof OutNode or node instanceof PostUpdateNode or - readDirect(_, _, node) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1072,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1086,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1109,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,307 +1146,365 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(config)) and +private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(node1, f, node2, config) and +private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) and nodeCand2(node1, config) and - nodeCand2(node2, _, true, unbind(config)) and - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(f, unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) + ) + or + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +pragma[nomagic] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) + ) +} + +/** + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. + */ +pragma[nomagic] +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and + toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) + ) + or + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + else returnApf = TAccessPathFrontNone() } pragma[nomagic] private predicate flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, + Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, apf0, config) and +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, apf, config) + ) +} + +pragma[nomagic] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +private newtype TAccessPathOption = + TAccessPathNone() or + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} + /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) -} - -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true ) } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) + ) +} + +/** + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. + */ +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + or + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and + ap instanceof AccessPathNil + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and + toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + ) + or + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() +} + +pragma[nomagic] +private predicate storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, f, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, ap0, unbind(config)) } pragma[nomagic] private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2050,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2303,7 +2240,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2255,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2347,7 +2284,7 @@ private predicate pathIntoLocalStep( pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2297,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2336,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2352,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2376,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2451,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2492,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2854,7 +2788,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..7a04c1f2a75 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -251,15 +251,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +289,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +368,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +379,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +506,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +543,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +557,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) + read(n1, f, n2) } pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) } -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) } pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and - nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) - ) -} - -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) -} - -pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) -} - -/** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +647,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,117 +659,126 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + store(mid, f, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, config) and + exists(Node mid, Content f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, unbind(config)) and + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,7 +1054,7 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or @@ -1292,7 +1062,7 @@ private module LocalFlowBigStep { node instanceof ParameterNode or node instanceof OutNode or node instanceof PostUpdateNode or - readDirect(_, _, node) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1072,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1086,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1109,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,307 +1146,365 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(config)) and +private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(node1, f, node2, config) and +private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) and nodeCand2(node1, config) and - nodeCand2(node2, _, true, unbind(config)) and - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(f, unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) + ) + or + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +pragma[nomagic] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) + ) +} + +/** + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. + */ +pragma[nomagic] +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and + toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) + ) + or + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + else returnApf = TAccessPathFrontNone() } pragma[nomagic] private predicate flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, + Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, apf0, config) and +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, apf, config) + ) +} + +pragma[nomagic] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +private newtype TAccessPathOption = + TAccessPathNone() or + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} + /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) -} - -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true ) } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) + ) +} + +/** + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. + */ +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + or + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and + ap instanceof AccessPathNil + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and + toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + ) + or + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() +} + +pragma[nomagic] +private predicate storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, f, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, ap0, unbind(config)) } pragma[nomagic] private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2050,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2303,7 +2240,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2255,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2347,7 +2284,7 @@ private predicate pathIntoLocalStep( pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2297,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2336,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2352,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2376,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2451,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2492,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2854,7 +2788,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll index 783ac641e6e..b241a574c97 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -26,13 +26,30 @@ private module Cached { ) } - /** Provides predicates for calculating flow-through summaries. */ + pragma[nomagic] + private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { + viableCallable(call) = result.getCallable() and + kind = result.getKind() + } + + /** + * Holds if a value at return position `pos` can be returned to `out` via `call`, + * taking virtual dispatch into account. + */ cached + predicate viableReturnPosOut(DataFlowCall call, ReturnPosition pos, Node out) { + exists(ReturnKindExt kind | + pos = viableReturnPos(call, kind) and + out = kind.getAnOutNode(call) + ) + } + + /** Provides predicates for calculating flow-through summaries. */ private module FlowThrough { /** * The first flow-through approximation: * - * - Input/output access paths are abstracted with a Boolean parameter + * - Input access paths are abstracted with a Boolean parameter * that indicates (non-)emptiness. */ private module Cand { @@ -40,83 +57,47 @@ private module Cached { * Holds if `p` can flow to `node` in the same callable using only * value-preserving steps. * - * `read` indicates whether it is contents of `p` that can flow to `node`, - * and `stored` indicates whether it flows to contents of `node`. + * `read` indicates whether it is contents of `p` that can flow to `node`. */ pragma[nomagic] - private predicate parameterValueFlowCand( - ParameterNode p, Node node, boolean read, boolean stored - ) { + private predicate parameterValueFlowCand(ParameterNode p, Node node, boolean read) { p = node and - read = false and - stored = false + read = false or // local flow exists(Node mid | - parameterValueFlowCand(p, mid, read, stored) and + parameterValueFlowCand(p, mid, read) and simpleLocalFlowStep(mid, node) ) or // read - exists(Node mid, boolean readMid, boolean storedMid | - parameterValueFlowCand(p, mid, readMid, storedMid) and - readStep(mid, _, node) and - stored = false - | - // value neither read nor stored prior to read - readMid = false and - storedMid = false and - read = true - or - // value (possibly read and then) stored prior to read (same content) - read = readMid and - storedMid = true - ) - or - // store exists(Node mid | - parameterValueFlowCand(p, mid, read, false) and - storeStep(mid, _, node) and - stored = true + parameterValueFlowCand(p, mid, false) and + readStep(mid, _, node) and + read = true ) or - // flow through: no prior read or store + // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArgCand(p, arg, false, false) and - argumentValueFlowsThroughCand(arg, node, read, stored) + parameterValueFlowArgCand(p, arg, false) and + argumentValueFlowsThroughCand(arg, node, read) ) or - // flow through: no read or store inside method + // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArgCand(p, arg, read, stored) and - argumentValueFlowsThroughCand(arg, node, false, false) - ) - or - // flow through: possible prior read and prior store with compatible - // flow-through method - exists(ArgumentNode arg, boolean mid | - parameterValueFlowArgCand(p, arg, read, mid) and - argumentValueFlowsThroughCand(arg, node, mid, stored) + parameterValueFlowArgCand(p, arg, read) and + argumentValueFlowsThroughCand(arg, node, false) ) } pragma[nomagic] - private predicate parameterValueFlowArgCand( - ParameterNode p, ArgumentNode arg, boolean read, boolean stored - ) { - parameterValueFlowCand(p, arg, read, stored) + private predicate parameterValueFlowArgCand(ParameterNode p, ArgumentNode arg, boolean read) { + parameterValueFlowCand(p, arg, read) } pragma[nomagic] predicate parameterValueFlowsToPreUpdateCand(ParameterNode p, PostUpdateNode n) { - parameterValueFlowCand(p, n.getPreUpdateNode(), false, false) - } - - pragma[nomagic] - private predicate parameterValueFlowsToPostUpdateCand( - ParameterNode p, PostUpdateNode n, boolean read - ) { - parameterValueFlowCand(p, n, read, true) + parameterValueFlowCand(p, n.getPreUpdateNode(), false) } /** @@ -125,33 +106,21 @@ private module Cached { * into account. * * `read` indicates whether it is contents of `p` that can flow to the return - * node, and `stored` indicates whether it flows to contents of the return * node. */ - predicate parameterValueFlowReturnCand( - ParameterNode p, ReturnKindExt kind, boolean read, boolean stored - ) { + predicate parameterValueFlowReturnCand(ParameterNode p, ReturnKind kind, boolean read) { exists(ReturnNode ret | - parameterValueFlowCand(p, ret, read, stored) and - kind = TValueReturn(ret.getKind()) - ) - or - exists(ParameterNode p2, int pos2, PostUpdateNode n | - parameterValueFlowsToPostUpdateCand(p, n, read) and - parameterValueFlowsToPreUpdateCand(p2, n) and - p2.isParameterOf(_, pos2) and - kind = TParamUpdate(pos2) and - p != p2 and - stored = true + parameterValueFlowCand(p, ret, read) and + kind = ret.getKind() ) } pragma[nomagic] private predicate argumentValueFlowsThroughCand0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, boolean read, boolean stored + DataFlowCall call, ArgumentNode arg, ReturnKind kind, boolean read ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturnCand(param, kind, read, stored) + parameterValueFlowReturnCand(param, kind, read) ) } @@ -159,22 +128,19 @@ private module Cached { * Holds if `arg` flows to `out` through a call using only value-preserving steps, * not taking call contexts into account. * - * `read` indicates whether it is contents of `arg` that can flow to `out`, and - * `stored` indicates whether it flows to contents of `out`. + * `read` indicates whether it is contents of `arg` that can flow to `out`. */ - predicate argumentValueFlowsThroughCand( - ArgumentNode arg, Node out, boolean read, boolean stored - ) { - exists(DataFlowCall call, ReturnKindExt kind | - argumentValueFlowsThroughCand0(call, arg, kind, read, stored) and - out = kind.getAnOutNode(call) + predicate argumentValueFlowsThroughCand(ArgumentNode arg, Node out, boolean read) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThroughCand0(call, arg, kind, read) and + out = getAnOutNode(call, kind) ) } predicate cand(ParameterNode p, Node n) { - parameterValueFlowCand(p, n, _, _) and + parameterValueFlowCand(p, n, _) and ( - parameterValueFlowReturnCand(p, _, _, _) + parameterValueFlowReturnCand(p, _, _) or parameterValueFlowsToPreUpdateCand(p, _) ) @@ -187,7 +153,6 @@ private module Cached { ( n instanceof ParameterNode or n instanceof OutNode or - n instanceof PostUpdateNode or readStep(_, _, n) or n instanceof CastNode ) @@ -200,10 +165,6 @@ private module Cached { or n instanceof ReturnNode or - Cand::parameterValueFlowsToPreUpdateCand(_, n) - or - storeStep(n, _, _) - or readStep(n, _, _) or n instanceof CastNode @@ -237,230 +198,140 @@ private module Cached { /** * The final flow-through calculation: * - * - Input/output access paths are abstracted with a `ContentOption` parameter + * - Input access paths are abstracted with a `ContentOption` parameter * that represents the head of the access path. `TContentNone()` means that * the access path is unrestricted. * - Types are checked using the `compatibleTypes()` relation. */ - cached private module Final { /** * Holds if `p` can flow to `node` in the same callable using only * value-preserving steps, not taking call contexts into account. * * `contentIn` describes the content of `p` that can flow to `node` - * (if any), and `contentOut` describes the content of `node` that - * it flows to (if any). + * (if any). */ - private predicate parameterValueFlow( - ParameterNode p, Node node, ContentOption contentIn, ContentOption contentOut - ) { - parameterValueFlow0(p, node, contentIn, contentOut) and + predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) { + parameterValueFlow0(p, node, contentIn) and if node instanceof CastingNode then // normal flow through contentIn = TContentNone() and - contentOut = TContentNone() and compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) or // getter exists(Content fIn | contentIn.getContent() = fIn and - contentOut = TContentNone() and compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node)) ) - or - // (getter+)setter - exists(Content fOut | - contentOut.getContent() = fOut and - compatibleTypes(fOut.getContainerType(), getErasedNodeTypeBound(node)) - ) else any() } pragma[nomagic] - private predicate parameterValueFlow0( - ParameterNode p, Node node, ContentOption contentIn, ContentOption contentOut - ) { + private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() and - contentOut = TContentNone() + contentIn = TContentNone() or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn, contentOut) and + parameterValueFlow(p, mid, contentIn) and LocalFlowBigStep::localFlowBigStep(mid, node) ) or // read - exists(Node mid, Content f, ContentOption contentInMid, ContentOption contentOutMid | - parameterValueFlow(p, mid, contentInMid, contentOutMid) and - readStep(mid, f, node) - | - // value neither read nor stored prior to read - contentInMid = TContentNone() and - contentOutMid = TContentNone() and - contentIn.getContent() = f and - contentOut = TContentNone() and - Cand::parameterValueFlowReturnCand(p, _, true, _) and - compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) - or - // value (possibly read and then) stored prior to read (same content) - contentIn = contentInMid and - contentOutMid.getContent() = f and - contentOut = TContentNone() - ) - or - // store exists(Node mid, Content f | - parameterValueFlow(p, mid, contentIn, TContentNone()) and - storeStep(mid, f, node) and - contentOut.getContent() = f - | - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(p), f.getType()) - or - compatibleTypes(contentIn.getContent().getType(), f.getType()) + parameterValueFlow(p, mid, TContentNone()) and + readStep(mid, f, node) and + contentIn.getContent() = f and + Cand::parameterValueFlowReturnCand(p, _, true) and + compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) ) or - // flow through: no prior read or store + // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, TContentNone(), TContentNone()) and - argumentValueFlowsThrough(_, arg, contentIn, contentOut, node) + parameterValueFlowArg(p, arg, TContentNone()) and + argumentValueFlowsThrough(arg, contentIn, node) ) or - // flow through: no read or store inside method + // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, contentIn, contentOut) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) - ) - or - // flow through: possible prior read and prior store with compatible - // flow-through method - exists(ArgumentNode arg, ContentOption contentMid | - parameterValueFlowArg(p, arg, contentIn, contentMid) and - argumentValueFlowsThrough(_, arg, contentMid, contentOut, node) + parameterValueFlowArg(p, arg, contentIn) and + argumentValueFlowsThrough(arg, TContentNone(), node) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn, ContentOption contentOut + ParameterNode p, ArgumentNode arg, ContentOption contentIn ) { - parameterValueFlow(p, arg, contentIn, contentOut) and - Cand::argumentValueFlowsThroughCand(arg, _, _, _) + parameterValueFlow(p, arg, contentIn) and + Cand::argumentValueFlowsThroughCand(arg, _, _) } pragma[nomagic] private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, ContentOption contentIn, - ContentOption contentOut + DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, _, kind, contentIn, contentOut) + parameterValueFlowReturn(param, kind, contentIn) ) } /** - * Holds if `arg` flows to `out` through `call` using only value-preserving steps, + * Holds if `arg` flows to `out` through a call using only value-preserving steps, * not taking call contexts into account. * - * `contentIn` describes the content of `arg` that can flow to `out` (if any), and - * `contentOut` describes the content of `out` that it flows to (if any). + * `contentIn` describes the content of `arg` that can flow to `out` (if any). */ - cached - predicate argumentValueFlowsThrough( - DataFlowCall call, ArgumentNode arg, ContentOption contentIn, ContentOption contentOut, - Node out - ) { - exists(ReturnKindExt kind | - argumentValueFlowsThrough0(call, arg, kind, contentIn, contentOut) and - out = kind.getAnOutNode(call) + pragma[nomagic] + predicate argumentValueFlowsThrough(ArgumentNode arg, ContentOption contentIn, Node out) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThrough0(call, arg, kind, contentIn) and + out = getAnOutNode(call, kind) | // normal flow through contentIn = TContentNone() and - contentOut = TContentNone() and compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) or // getter exists(Content fIn | contentIn.getContent() = fIn and - contentOut = TContentNone() and compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out)) ) - or - // setter - exists(Content fOut | - contentIn = TContentNone() and - contentOut.getContent() = fOut and - compatibleTypes(getErasedNodeTypeBound(arg), fOut.getType()) and - compatibleTypes(fOut.getContainerType(), getErasedNodeTypeBound(out)) - ) - or - // getter+setter - exists(Content fIn, Content fOut | - contentIn.getContent() = fIn and - contentOut.getContent() = fOut and - compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and - compatibleTypes(fOut.getContainerType(), getErasedNodeTypeBound(out)) - ) ) } - /** - * Holds if `p` can flow to the pre-update node associated with post-update - * node `n`, in the same callable, using only value-preserving steps. - */ - cached - predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone(), TContentNone()) - } - - pragma[nomagic] - private predicate parameterValueFlowsToPostUpdate( - ParameterNode p, PostUpdateNode n, ContentOption contentIn, ContentOption contentOut - ) { - parameterValueFlow(p, n, contentIn, contentOut) and - contentOut.hasContent() - } - /** * Holds if `p` can flow to a return node of kind `kind` in the same * callable using only value-preserving steps. * * `contentIn` describes the content of `p` that can flow to the return - * node (if any), and `contentOut` describes the content of the return - * node that it flows to (if any). + * node (if any). */ - cached - predicate parameterValueFlowReturn( - ParameterNode p, Node ret, ReturnKindExt kind, ContentOption contentIn, - ContentOption contentOut + private predicate parameterValueFlowReturn( + ParameterNode p, ReturnKind kind, ContentOption contentIn ) { - ret = - any(ReturnNode n | - parameterValueFlow(p, n, contentIn, contentOut) and - kind = TValueReturn(n.getKind()) - ) - or - ret = - any(PostUpdateNode n | - exists(ParameterNode p2, int pos2 | - parameterValueFlowsToPostUpdate(p, n, contentIn, contentOut) and - parameterValueFlowsToPreUpdate(p2, n) and - p2.isParameterOf(_, pos2) and - kind = TParamUpdate(pos2) and - p != p2 - ) - ) + exists(ReturnNode ret | + parameterValueFlow(p, ret, contentIn) and + kind = ret.getKind() + ) } } import Final } + /** + * Holds if `p` can flow to the pre-update node associated with post-update + * node `n`, in the same callable, using only value-preserving steps. + */ + cached + predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { + parameterValueFlow(p, n.getPreUpdateNode(), TContentNone()) + } + /** * Holds if data can flow from `node1` to `node2` via a direct assignment to * `f`. @@ -469,14 +340,14 @@ private module Cached { * been stored into, in order to handle cases like `x.f1.f2 = y`. */ cached - predicate storeDirect(Node node1, Content f, Node node2) { + predicate store(Node node1, Content f, Node node2) { storeStep(node1, f, node2) and readStep(_, f, _) or exists(Node n1, Node n2 | n1 = node1.(PostUpdateNode).getPreUpdateNode() and n2 = node2.(PostUpdateNode).getPreUpdateNode() | - argumentValueFlowsThrough(_, n2, TContentSome(f), TContentNone(), n1) + argumentValueFlowsThrough(n2, TContentSome(f), n1) or readStep(n2, f, n1) ) @@ -520,6 +391,21 @@ private module Cached { newtype TReturnKindExt = TValueReturn(ReturnKind kind) or TParamUpdate(int pos) { exists(ParameterNode p | p.isParameterOf(_, pos)) } + + cached + newtype TBooleanOption = + TBooleanNone() or + TBooleanSome(boolean b) { b = true or b = false } + + cached + newtype TAccessPathFront = + TFrontNil(DataFlowType t) or + TFrontHead(Content f) + + cached + newtype TAccessPathFrontOption = + TAccessPathFrontNone() or + TAccessPathFrontSome(AccessPathFront apf) } /** @@ -538,7 +424,7 @@ newtype TContentOption = TContentNone() or TContentSome(Content f) -class ContentOption extends TContentOption { +private class ContentOption extends TContentOption { Content getContent() { this = TContentSome(result) } predicate hasContent() { exists(this.getContent()) } @@ -779,77 +665,58 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { result = viableCallable(call) and cc instanceof CallContextReturn } -newtype TSummary = - TSummaryVal() or - TSummaryTaint() or - TSummaryReadVal(Content f) or - TSummaryReadTaint(Content f) or - TSummaryTaintStore(Content f) - -/** - * A summary of flow through a callable. This can either be value-preserving - * if no additional steps are used, taint-flow if at least one additional step - * is used, or any one of those combined with a store or a read. Summaries - * recorded at a return node are restricted to include at least one additional - * step, as the value-based summaries are calculated independent of the - * configuration. - */ -class Summary extends TSummary { - string toString() { - result = "Val" and this = TSummaryVal() - or - result = "Taint" and this = TSummaryTaint() - or - exists(Content f | - result = "ReadVal " + f.toString() and this = TSummaryReadVal(f) - or - result = "ReadTaint " + f.toString() and this = TSummaryReadTaint(f) - or - result = "TaintStore " + f.toString() and this = TSummaryTaintStore(f) - ) - } - - /** Gets the summary that results from extending this with an additional step. */ - Summary additionalStep() { - this = TSummaryVal() and result = TSummaryTaint() - or - this = TSummaryTaint() and result = TSummaryTaint() - or - exists(Content f | this = TSummaryReadVal(f) and result = TSummaryReadTaint(f)) - or - exists(Content f | this = TSummaryReadTaint(f) and result = TSummaryReadTaint(f)) - } - - /** Gets the summary that results from extending this with a read. */ - Summary readStep(Content f) { this = TSummaryVal() and result = TSummaryReadVal(f) } - - /** Gets the summary that results from extending this with a store. */ - Summary storeStep(Content f) { this = TSummaryTaint() and result = TSummaryTaintStore(f) } - - /** Gets the summary that results from extending this with `step`. */ - bindingset[this, step] - Summary compose(Summary step) { - this = TSummaryVal() and result = step - or - this = TSummaryTaint() and - (step = TSummaryTaint() or step = TSummaryTaintStore(_)) and - result = step - or - exists(Content f | - this = TSummaryReadVal(f) and step = TSummaryTaint() and result = TSummaryReadTaint(f) - ) - or - this = TSummaryReadTaint(_) and step = TSummaryTaint() and result = this - } - - /** Holds if this summary does not include any taint steps. */ - predicate isPartial() { - this = TSummaryVal() or - this = TSummaryReadVal(_) - } -} - pragma[noinline] DataFlowType getErasedNodeTypeBound(Node n) { result = getErasedRepr(n.getTypeBound()) } -predicate readDirect = readStep/3; +predicate read = readStep/3; + +/** An optional Boolean value. */ +class BooleanOption extends TBooleanOption { + string toString() { + this = TBooleanNone() and result = "" + or + this = TBooleanSome(any(boolean b | result = b.toString())) + } +} + +/** + * The front of an access path. This is either a head or a nil. + */ +abstract class AccessPathFront extends TAccessPathFront { + abstract string toString(); + + abstract DataFlowType getType(); + + abstract boolean toBoolNonEmpty(); + + predicate headUsesContent(Content f) { this = TFrontHead(f) } +} + +class AccessPathFrontNil extends AccessPathFront, TFrontNil { + override string toString() { + exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) + } + + override DataFlowType getType() { this = TFrontNil(result) } + + override boolean toBoolNonEmpty() { result = false } +} + +class AccessPathFrontHead extends AccessPathFront, TFrontHead { + override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } + + override DataFlowType getType() { + exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) + } + + override boolean toBoolNonEmpty() { result = true } +} + +/** An optional access path front. */ +class AccessPathFrontOption extends TAccessPathFrontOption { + string toString() { + this = TAccessPathFrontNone() and result = "" + or + this = TAccessPathFrontSome(any(AccessPathFront apf | result = apf.toString())) + } +} From 05ec75558d7fec84a42db4f1c6bb84d2e0ca27ec Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 17 Mar 2020 16:24:58 +0100 Subject: [PATCH 0182/1298] Java: Update test --- .../dataflow/{gettersetter => getter}/A.java | 0 .../dataflow/getter/getter.expected | 6 ++++++ .../library-tests/dataflow/getter/getter.ql | 10 +++++++++ .../gettersetter/gettersetter.expected | 10 --------- .../dataflow/gettersetter/gettersetter.ql | 21 ------------------- 5 files changed, 16 insertions(+), 31 deletions(-) rename java/ql/test/library-tests/dataflow/{gettersetter => getter}/A.java (100%) create mode 100644 java/ql/test/library-tests/dataflow/getter/getter.expected create mode 100644 java/ql/test/library-tests/dataflow/getter/getter.ql delete mode 100644 java/ql/test/library-tests/dataflow/gettersetter/gettersetter.expected delete mode 100644 java/ql/test/library-tests/dataflow/gettersetter/gettersetter.ql diff --git a/java/ql/test/library-tests/dataflow/gettersetter/A.java b/java/ql/test/library-tests/dataflow/getter/A.java similarity index 100% rename from java/ql/test/library-tests/dataflow/gettersetter/A.java rename to java/ql/test/library-tests/dataflow/getter/A.java diff --git a/java/ql/test/library-tests/dataflow/getter/getter.expected b/java/ql/test/library-tests/dataflow/getter/getter.expected new file mode 100644 index 00000000000..b5af3f91a59 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/getter/getter.expected @@ -0,0 +1,6 @@ +| A.java:5:12:5:15 | this | A.java:5:12:5:19 | this.foo | A.java:2:7:2:9 | foo | +| A.java:21:13:21:13 | a | A.java:21:13:21:22 | getFoo(...) | A.java:2:7:2:9 | foo | +| A.java:23:9:23:9 | a | A.java:23:9:23:19 | aGetter(...) | A.java:2:7:2:9 | foo | +| A.java:24:9:24:10 | a2 | A.java:24:9:24:23 | notAGetter(...) | A.java:2:7:2:9 | foo | +| A.java:45:12:45:38 | maybeIdWrap(...) | A.java:45:12:45:42 | maybeIdWrap(...).foo | A.java:2:7:2:9 | foo | +| A.java:49:12:49:38 | maybeIdWrap(...) | A.java:49:12:49:42 | maybeIdWrap(...).foo | A.java:2:7:2:9 | foo | diff --git a/java/ql/test/library-tests/dataflow/getter/getter.ql b/java/ql/test/library-tests/dataflow/getter/getter.ql new file mode 100644 index 00000000000..22ee7be5a12 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/getter/getter.ql @@ -0,0 +1,10 @@ +import java +import semmle.code.java.dataflow.internal.DataFlowImplCommon +import semmle.code.java.dataflow.internal.DataFlowImplSpecific::Public +import semmle.code.java.dataflow.internal.DataFlowImplSpecific::Private + +from Node n1, Content f, Node n2 +where + read(n1, f, n2) or + argumentValueFlowsThrough(n1, TContentSome(f), n2) +select n1, n2, f diff --git a/java/ql/test/library-tests/dataflow/gettersetter/gettersetter.expected b/java/ql/test/library-tests/dataflow/gettersetter/gettersetter.expected deleted file mode 100644 index ba081588706..00000000000 --- a/java/ql/test/library-tests/dataflow/gettersetter/gettersetter.expected +++ /dev/null @@ -1,10 +0,0 @@ -| Read | A.java:5:12:5:15 | this | A.java:5:12:5:19 | this.foo | A.java:2:7:2:9 | foo | -| Read | A.java:21:13:21:13 | a | A.java:21:13:21:22 | getFoo(...) | A.java:2:7:2:9 | foo | -| Read | A.java:23:9:23:9 | a | A.java:23:9:23:19 | aGetter(...) | A.java:2:7:2:9 | foo | -| Read | A.java:24:9:24:10 | a2 | A.java:24:9:24:23 | notAGetter(...) | A.java:2:7:2:9 | foo | -| Read | A.java:45:12:45:38 | maybeIdWrap(...) | A.java:45:12:45:42 | maybeIdWrap(...).foo | A.java:2:7:2:9 | foo | -| Read | A.java:49:12:49:38 | maybeIdWrap(...) | A.java:49:12:49:42 | maybeIdWrap(...).foo | A.java:2:7:2:9 | foo | -| Store | A.java:9:16:9:16 | x | A.java:9:5:9:8 | this [post update] | A.java:2:7:2:9 | foo | -| Store | A.java:14:13:14:13 | x | A.java:14:5:14:5 | a [post update] | A.java:2:7:2:9 | foo | -| Store | A.java:20:14:20:14 | 1 | A.java:20:5:20:5 | a [post update] | A.java:2:7:2:9 | foo | -| Store | A.java:22:20:22:20 | 2 | A.java:22:12:22:21 | withFoo(...) | A.java:2:7:2:9 | foo | diff --git a/java/ql/test/library-tests/dataflow/gettersetter/gettersetter.ql b/java/ql/test/library-tests/dataflow/gettersetter/gettersetter.ql deleted file mode 100644 index ce802982d99..00000000000 --- a/java/ql/test/library-tests/dataflow/gettersetter/gettersetter.ql +++ /dev/null @@ -1,21 +0,0 @@ -import java -import semmle.code.java.dataflow.internal.DataFlowImplCommon -import semmle.code.java.dataflow.internal.DataFlowImplSpecific::Public -import semmle.code.java.dataflow.internal.DataFlowImplSpecific::Private - -private predicate read(Node n1, Content f, Node n2) { - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) -} - -private predicate store(Node n1, Content f, Node n2) { - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) -} - -from Node n1, Content f, Node n2, string k -where - read(n1, f, n2) and k = "Read" - or - store(n1, f, n2) and k = "Store" -select k, n1, n2, f From f91af7daf352183408f9e5a0bbee5490da7cca60 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 18 Mar 2020 20:45:28 +0100 Subject: [PATCH 0183/1298] C#: Add more data-flow tests --- .../dataflow/callablereturnsarg/Common.qll | 27 +++++++++------- .../dataflow/fields/FieldFlow.expected | 32 +++++++++++++++++++ .../test/library-tests/dataflow/fields/H.cs | 17 ++++++++++ .../library-tests/dataflow/types/Types.cs | 12 +++++++ .../dataflow/types/Types.expected | 12 +++++++ 5 files changed, 89 insertions(+), 11 deletions(-) diff --git a/csharp/ql/test/library-tests/dataflow/callablereturnsarg/Common.qll b/csharp/ql/test/library-tests/dataflow/callablereturnsarg/Common.qll index 4b2626c73b3..2ddbd6cf123 100644 --- a/csharp/ql/test/library-tests/dataflow/callablereturnsarg/Common.qll +++ b/csharp/ql/test/library-tests/dataflow/callablereturnsarg/Common.qll @@ -1,12 +1,23 @@ import csharp private import semmle.code.csharp.controlflow.Guards +private predicate outRefDef(DataFlow::ExprNode ne, int outRef) { + exists(Ssa::ExplicitDefinition def, Parameter outRefParameter | + outRefParameter.isOutOrRef() and + ne.getExpr() = def.getADefinition().getSource() and + def.isLiveOutRefParameterDefinition(outRefParameter) and + outRef = outRefParameter.getPosition() + ) +} + class Configuration extends DataFlow::Configuration { Configuration() { this = "Configuration" } - override predicate isSource(DataFlow::Node source) { any() } + override predicate isSource(DataFlow::Node source) { source instanceof DataFlow::ParameterNode } - override predicate isSink(DataFlow::Node sink) { any() } + override predicate isSink(DataFlow::Node sink) { + any(Callable c).canReturn(sink.asExpr()) or outRefDef(sink, _) + } override predicate isBarrier(DataFlow::Node node) { exists(AbstractValues::NullValue nv | node.(GuardedDataFlowNode).mustHaveValue(nv) | @@ -24,15 +35,9 @@ predicate flowOutFromParameter(DataFlow::Configuration c, Parameter p) { } predicate flowOutFromParameterOutOrRef(DataFlow::Configuration c, Parameter p, int outRef) { - exists( - DataFlow::ExprNode ne, Ssa::ExplicitDefinition def, DataFlow::ParameterNode np, - Parameter outRefParameter - | - outRefParameter.isOutOrRef() and + exists(DataFlow::ExprNode ne, DataFlow::ParameterNode np | + outRefDef(ne, outRef) and np.getParameter() = p and - ne.getExpr() = def.getADefinition().getSource() and - def.isLiveOutRefParameterDefinition(outRefParameter) and - c.hasFlow(np, ne) and - outRef = outRefParameter.getPosition() + c.hasFlow(np, ne) ) } diff --git a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected index baae38c1780..3d0a0a83ed5 100644 --- a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected @@ -201,6 +201,20 @@ edges | H.cs:131:18:131:18 | access to local variable a [FieldA] : Object | H.cs:131:14:131:19 | call to method Get | | H.cs:147:17:147:32 | call to method Through : A | H.cs:148:14:148:14 | access to local variable a | | H.cs:147:25:147:31 | object creation of type A : A | H.cs:147:17:147:32 | call to method Through : A | +| H.cs:155:17:155:23 | object creation of type B : B | H.cs:157:20:157:20 | access to local variable b : B | +| H.cs:157:9:157:9 | [post] access to parameter a [FieldA] : B | H.cs:164:19:164:19 | [post] access to local variable a [FieldA] : B | +| H.cs:157:20:157:20 | access to local variable b : B | H.cs:157:9:157:9 | [post] access to parameter a [FieldA] : B | +| H.cs:163:17:163:28 | object creation of type Object : Object | H.cs:164:22:164:22 | access to local variable o : Object | +| H.cs:164:19:164:19 | [post] access to local variable a [FieldA, FieldB] | H.cs:165:21:165:21 | access to local variable a [FieldA, FieldB] | +| H.cs:164:19:164:19 | [post] access to local variable a [FieldA] : B | H.cs:165:21:165:21 | access to local variable a [FieldA] : B | +| H.cs:164:22:164:22 | access to local variable o : Object | H.cs:164:19:164:19 | [post] access to local variable a [FieldA, FieldB] | +| H.cs:165:17:165:28 | (...) ... : B | H.cs:166:14:166:14 | access to local variable b | +| H.cs:165:17:165:28 | (...) ... [FieldB] : Object | H.cs:167:14:167:14 | access to local variable b [FieldB] : Object | +| H.cs:165:21:165:21 | access to local variable a [FieldA, FieldB] | H.cs:165:21:165:28 | access to field FieldA [FieldB] : Object | +| H.cs:165:21:165:21 | access to local variable a [FieldA] : B | H.cs:165:21:165:28 | access to field FieldA : B | +| H.cs:165:21:165:28 | access to field FieldA : B | H.cs:165:17:165:28 | (...) ... : B | +| H.cs:165:21:165:28 | access to field FieldA [FieldB] : Object | H.cs:165:17:165:28 | (...) ... [FieldB] : Object | +| H.cs:167:14:167:14 | access to local variable b [FieldB] : Object | H.cs:167:14:167:21 | access to field FieldB | nodes | A.cs:5:17:5:23 | object creation of type C : C | semmle.label | object creation of type C : C | | A.cs:6:17:6:25 | call to method Make [c] : C | semmle.label | call to method Make [c] : C | @@ -434,6 +448,22 @@ nodes | H.cs:147:17:147:32 | call to method Through : A | semmle.label | call to method Through : A | | H.cs:147:25:147:31 | object creation of type A : A | semmle.label | object creation of type A : A | | H.cs:148:14:148:14 | access to local variable a | semmle.label | access to local variable a | +| H.cs:155:17:155:23 | object creation of type B : B | semmle.label | object creation of type B : B | +| H.cs:157:9:157:9 | [post] access to parameter a [FieldA] : B | semmle.label | [post] access to parameter a [FieldA] : B | +| H.cs:157:20:157:20 | access to local variable b : B | semmle.label | access to local variable b : B | +| H.cs:163:17:163:28 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| H.cs:164:19:164:19 | [post] access to local variable a [FieldA, FieldB] | semmle.label | [post] access to local variable a [FieldA, FieldB] | +| H.cs:164:19:164:19 | [post] access to local variable a [FieldA] : B | semmle.label | [post] access to local variable a [FieldA] : B | +| H.cs:164:22:164:22 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| H.cs:165:17:165:28 | (...) ... : B | semmle.label | (...) ... : B | +| H.cs:165:17:165:28 | (...) ... [FieldB] : Object | semmle.label | (...) ... [FieldB] : Object | +| H.cs:165:21:165:21 | access to local variable a [FieldA, FieldB] | semmle.label | access to local variable a [FieldA, FieldB] | +| H.cs:165:21:165:21 | access to local variable a [FieldA] : B | semmle.label | access to local variable a [FieldA] : B | +| H.cs:165:21:165:28 | access to field FieldA : B | semmle.label | access to field FieldA : B | +| H.cs:165:21:165:28 | access to field FieldA [FieldB] : Object | semmle.label | access to field FieldA [FieldB] : Object | +| H.cs:166:14:166:14 | access to local variable b | semmle.label | access to local variable b | +| H.cs:167:14:167:14 | access to local variable b [FieldB] : Object | semmle.label | access to local variable b [FieldB] : Object | +| H.cs:167:14:167:21 | access to field FieldB | semmle.label | access to field FieldB | #select | A.cs:7:14:7:16 | access to field c | A.cs:5:17:5:23 | object creation of type C : C | A.cs:7:14:7:16 | access to field c | $@ | A.cs:5:17:5:23 | object creation of type C : C | object creation of type C : C | | A.cs:14:14:14:20 | call to method Get | A.cs:13:15:13:22 | object creation of type C1 : C1 | A.cs:14:14:14:20 | call to method Get | $@ | A.cs:13:15:13:22 | object creation of type C1 : C1 | object creation of type C1 : C1 | @@ -481,3 +511,5 @@ nodes | H.cs:114:14:114:21 | access to field FieldB | H.cs:112:20:112:31 | object creation of type Object : Object | H.cs:114:14:114:21 | access to field FieldB | $@ | H.cs:112:20:112:31 | object creation of type Object : Object | object creation of type Object : Object | | H.cs:131:14:131:19 | call to method Get | H.cs:130:20:130:31 | object creation of type Object : Object | H.cs:131:14:131:19 | call to method Get | $@ | H.cs:130:20:130:31 | object creation of type Object : Object | object creation of type Object : Object | | H.cs:148:14:148:14 | access to local variable a | H.cs:147:25:147:31 | object creation of type A : A | H.cs:148:14:148:14 | access to local variable a | $@ | H.cs:147:25:147:31 | object creation of type A : A | object creation of type A : A | +| H.cs:166:14:166:14 | access to local variable b | H.cs:155:17:155:23 | object creation of type B : B | H.cs:166:14:166:14 | access to local variable b | $@ | H.cs:155:17:155:23 | object creation of type B : B | object creation of type B : B | +| H.cs:167:14:167:21 | access to field FieldB | H.cs:163:17:163:28 | object creation of type Object : Object | H.cs:167:14:167:21 | access to field FieldB | $@ | H.cs:163:17:163:28 | object creation of type Object : Object | object creation of type Object : Object | diff --git a/csharp/ql/test/library-tests/dataflow/fields/H.cs b/csharp/ql/test/library-tests/dataflow/fields/H.cs index 1ddb6ec2821..1d214fc89da 100644 --- a/csharp/ql/test/library-tests/dataflow/fields/H.cs +++ b/csharp/ql/test/library-tests/dataflow/fields/H.cs @@ -150,5 +150,22 @@ public class H Sink(b); // no flow } + void SetNested(A a, object o) + { + var b = new B(); + b.FieldB = o; + a.FieldA = b; + } + + void M8() + { + var a = new A(); + var o = new object(); + SetNested(a, o); + var b = (B) a.FieldA; + Sink(b); // flow (from `new B()` inside `SetNested`) + Sink(b.FieldB); // flow + } + public static void Sink(object o) { } } \ No newline at end of file diff --git a/csharp/ql/test/library-tests/dataflow/types/Types.cs b/csharp/ql/test/library-tests/dataflow/types/Types.cs index a768fc83135..92f60ec551e 100644 --- a/csharp/ql/test/library-tests/dataflow/types/Types.cs +++ b/csharp/ql/test/library-tests/dataflow/types/Types.cs @@ -114,6 +114,18 @@ class Types { Sink(this.Field); } + + void M10() + { + var a = new A(); + var e2 = new E2(); + Sink(Through(a)); // flow + Sink(Through(e2)); // flow + Sink((E2)Through(a)); // no flow + Sink((A)Through(e2)); // no flow + } } } + + static object Through(object x) => x; } diff --git a/csharp/ql/test/library-tests/dataflow/types/Types.expected b/csharp/ql/test/library-tests/dataflow/types/Types.expected index 40e9c750a12..15dd073b91d 100644 --- a/csharp/ql/test/library-tests/dataflow/types/Types.expected +++ b/csharp/ql/test/library-tests/dataflow/types/Types.expected @@ -39,6 +39,10 @@ edges | Types.cs:110:25:110:32 | object creation of type E2 : E2 | Types.cs:90:22:90:22 | e : E2 | | Types.cs:113:34:113:34 | this [Field] : E2 | Types.cs:115:22:115:25 | this access [Field] : E2 | | Types.cs:115:22:115:25 | this access [Field] : E2 | Types.cs:115:22:115:31 | access to field Field | +| Types.cs:120:25:120:31 | object creation of type A : A | Types.cs:122:30:122:30 | access to local variable a : A | +| Types.cs:121:26:121:33 | object creation of type E2 : E2 | Types.cs:123:30:123:31 | access to local variable e2 : E2 | +| Types.cs:122:30:122:30 | access to local variable a : A | Types.cs:122:22:122:31 | call to method Through | +| Types.cs:123:30:123:31 | access to local variable e2 : E2 | Types.cs:123:22:123:32 | call to method Through | nodes | Types.cs:7:21:7:25 | this : D | semmle.label | this : D | | Types.cs:7:32:7:35 | this access : D | semmle.label | this access : D | @@ -90,6 +94,12 @@ nodes | Types.cs:113:34:113:34 | this [Field] : E2 | semmle.label | this [Field] : E2 | | Types.cs:115:22:115:25 | this access [Field] : E2 | semmle.label | this access [Field] : E2 | | Types.cs:115:22:115:31 | access to field Field | semmle.label | access to field Field | +| Types.cs:120:25:120:31 | object creation of type A : A | semmle.label | object creation of type A : A | +| Types.cs:121:26:121:33 | object creation of type E2 : E2 | semmle.label | object creation of type E2 : E2 | +| Types.cs:122:22:122:31 | call to method Through | semmle.label | call to method Through | +| Types.cs:122:30:122:30 | access to local variable a : A | semmle.label | access to local variable a : A | +| Types.cs:123:22:123:32 | call to method Through | semmle.label | call to method Through | +| Types.cs:123:30:123:31 | access to local variable e2 : E2 | semmle.label | access to local variable e2 : E2 | #select | Types.cs:23:12:23:18 | object creation of type C : C | Types.cs:50:18:50:18 | access to local variable c | Types.cs:50:18:50:18 | access to local variable c | $@ | Types.cs:50:18:50:18 | access to local variable c | access to local variable c | | Types.cs:25:12:25:18 | object creation of type C : C | Types.cs:63:33:63:36 | (...) ... | Types.cs:63:33:63:36 | (...) ... | $@ | Types.cs:63:33:63:36 | (...) ... | (...) ... | @@ -106,3 +116,5 @@ nodes | Types.cs:40:12:40:18 | object creation of type D : D | Types.cs:16:42:16:45 | this access | Types.cs:16:42:16:45 | this access | $@ | Types.cs:16:42:16:45 | this access | this access | | Types.cs:43:20:43:23 | null : null | Types.cs:44:14:44:14 | access to local variable o | Types.cs:44:14:44:14 | access to local variable o | $@ | Types.cs:44:14:44:14 | access to local variable o | access to local variable o | | Types.cs:110:25:110:32 | object creation of type E2 : E2 | Types.cs:115:22:115:31 | access to field Field | Types.cs:115:22:115:31 | access to field Field | $@ | Types.cs:115:22:115:31 | access to field Field | access to field Field | +| Types.cs:120:25:120:31 | object creation of type A : A | Types.cs:122:22:122:31 | call to method Through | Types.cs:122:22:122:31 | call to method Through | $@ | Types.cs:122:22:122:31 | call to method Through | call to method Through | +| Types.cs:121:26:121:33 | object creation of type E2 : E2 | Types.cs:123:22:123:32 | call to method Through | Types.cs:123:22:123:32 | call to method Through | $@ | Types.cs:123:22:123:32 | call to method Through | call to method Through | From 01a31c106512c708d9eb1f02d45be4572c7194d3 Mon Sep 17 00:00:00 2001 From: Felicity Chapman Date: Fri, 17 Apr 2020 12:50:20 +0100 Subject: [PATCH 0184/1298] Minor editorial changes --- change-notes/1.24/analysis-javascript.md | 26 ++++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/change-notes/1.24/analysis-javascript.md b/change-notes/1.24/analysis-javascript.md index b884fa4b66d..0c2172bac7a 100644 --- a/change-notes/1.24/analysis-javascript.md +++ b/change-notes/1.24/analysis-javascript.md @@ -4,22 +4,22 @@ * TypeScript 3.8 is now supported. -* Alert suppression can now be done with single-line block comments (`/* ... */`) as well as line comments (`// ...`). +* You can now suppress alerts using either single-line block comments (`/* ... */`) or line comments (`// ...`). * Resolution of imports has improved, leading to more results from the security queries: - Imports with the `.js` extension can now be resolved to a TypeScript file, - when the import refers to a file generated by TypeScript. + when the import refers to a file generated by TypeScript. - Imports that rely on path-mappings from a `tsconfig.json` file can now be resolved. - Export declarations of the form `export * as ns from "x"` are now analyzed more precisely. * The analysis of sanitizers has improved, leading to more accurate results from the security queries. In particular: - - Sanitizer guards now act across function boundaries in more cases. - - Sanitizers can now better distinguish between a tainted value and an object _containing_ a tainted value. + - Sanitizer guards now act across function boundaries in more cases. + - Sanitizers can now better distinguish between a tainted value and an object _containing_ a tainted value. * Call graph construction has been improved, leading to more results from the security queries: - - Calls can now be resolved to indirectly-defined class members in more cases. - - Calls through partial invocations such as `.bind` can now be resolved in more cases. + - Calls can now be resolved to indirectly-defined class members in more cases. + - Calls through partial invocations such as `.bind` can now be resolved in more cases. * Support for flow summaries has been more clearly marked as being experimental and moved to the new `experimental` folder. @@ -74,20 +74,20 @@ | **Query** | **Expected impact** | **Change** | |--------------------------------|------------------------------|---------------------------------------------------------------------------| | Clear-text logging of sensitive information (`js/clear-text-logging`) | More results | More results involving `process.env` and indirect calls to logging methods are recognized. | -| Duplicate parameter names (`js/duplicate-parameter-name`) | Fewer results | This query now recognizes additional parameters that reasonably can have duplicated names. | +| Duplicate parameter names (`js/duplicate-parameter-name`) | Fewer results | This query now ignores additional parameters that reasonably can have duplicated names. | | Expression has no effect (`js/useless-expression`) | Fewer false positive results | The query now recognizes block-level flow type annotations and ignores the first statement of a try block. | -| Identical operands (`js/redundant-operation`) | Fewer results | This query now recognizes cases where the operands change a value using ++/-- expressions. | -| Incomplete string escaping or encoding (`js/incomplete-sanitization`) | Fewer false positive results | This query now recognizes additional cases where a single replacement is likely to be intentional. | +| Identical operands (`js/redundant-operation`) | Fewer results | This query now excludes cases where the operands change a value using ++/-- expressions. | +| Incomplete string escaping or encoding (`js/incomplete-sanitization`) | Fewer false positive results | This query now recognizes and excludes additional cases where a single replacement is likely to be intentional. | | Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes more variations of URL scheme checks. | | Missing CSRF middleware (`js/missing-token-validation`) | Fewer false positive results | The query reports fewer duplicates and only flags handlers that explicitly access cookie data. | -| Superfluous trailing arguments (`js/superfluous-trailing-arguments`) | Fewer results | This query now recognizes cases where a function uses the `Function.arguments` value to process a variable number of parameters. | +| Superfluous trailing arguments (`js/superfluous-trailing-arguments`) | Fewer results | This query now excludes cases where a function uses the `Function.arguments` value to process a variable number of parameters. | | Syntax error (`js/syntax-error`) | Lower severity | This results of this query are now displayed with lower severity. | | Unbound event handler receiver (`js/unbound-event-handler-receiver`) | Fewer false positive results | This query now recognizes additional ways event handler receivers can be bound. | | Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional ways of constructing arguments to `cmd.exe` and `/bin/sh`. | | Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional ways dangerous paths can be constructed and used. | | Use of call stack introspection in strict mode (`js/strict-mode-call-stack-introspection`) | Fewer false positive results | The query no longer flags expression statements. | -| Use of password hash with insufficient computational effort (`js/insufficient-password-hash`) | Fewer false positive results | This query now recognizes additional cases that do not require secure hashing. | -| Useless regular-expression character escape (`js/useless-regexp-character-escape`) | Fewer false positive results | This query now distinguishes escapes in strings and regular expression literals. | +| Use of password hash with insufficient computational effort (`js/insufficient-password-hash`) | Fewer false positive results | This query now recognizes and excludes additional cases that do not require secure hashing. | +| Useless regular-expression character escape (`js/useless-regexp-character-escape`) | Fewer false positive results | This query now distinguishes between escapes in strings and regular expression literals. | ## Changes to libraries @@ -97,4 +97,4 @@ that combine taint-tracking and flow labels. - Sources added by the 1-argument `isSource` predicate are associated with the `taint` label now, instead of the `data` label. - Sanitizers now only block the `taint` label. As a result, sanitizers no longer block the flow of tainted values wrapped inside a property of an object. - To retain the old behavior, instead use a barrier, or block the `data` flow label using a labeled sanitizer. + To retain the old behavior, instead use a barrier, or block the `data` flow label using a labeled sanitizer. From 225dc4b01790bb21e48643ff944eddca04067a13 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 17 Apr 2020 13:54:48 +0200 Subject: [PATCH 0185/1298] change-note --- change-notes/1.24/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.24/analysis-javascript.md b/change-notes/1.24/analysis-javascript.md index 0e92d66033d..e2f7141c146 100644 --- a/change-notes/1.24/analysis-javascript.md +++ b/change-notes/1.24/analysis-javascript.md @@ -87,6 +87,7 @@ | Identical operands (`js/redundant-operation`) | Fewer results | This query now recognizes cases where the operands change a value using ++/-- expressions. | | Superfluous trailing arguments (`js/superfluous-trailing-arguments`) | Fewer results | This query now recognizes cases where a function uses the `Function.arguments` value to process a variable number of parameters. | | Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes more variations of URL scheme checks. | +| Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in more cases. | ## Changes to libraries From 88f600fa3496dfc5e8baa534eb06e768f4cf3cbe Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 17 Apr 2020 14:14:08 +0200 Subject: [PATCH 0186/1298] more -> additional Co-Authored-By: Esben Sparre Andreasen --- change-notes/1.24/analysis-javascript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.24/analysis-javascript.md b/change-notes/1.24/analysis-javascript.md index e2f7141c146..bba72368168 100644 --- a/change-notes/1.24/analysis-javascript.md +++ b/change-notes/1.24/analysis-javascript.md @@ -87,7 +87,7 @@ | Identical operands (`js/redundant-operation`) | Fewer results | This query now recognizes cases where the operands change a value using ++/-- expressions. | | Superfluous trailing arguments (`js/superfluous-trailing-arguments`) | Fewer results | This query now recognizes cases where a function uses the `Function.arguments` value to process a variable number of parameters. | | Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes more variations of URL scheme checks. | -| Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in more cases. | +| Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. | ## Changes to libraries From a2ddf7bf8fc395274911a3a1d422829647b9dbb1 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 17 Apr 2020 14:19:17 +0200 Subject: [PATCH 0187/1298] retarget change-note for 1.25 --- change-notes/1.24/analysis-javascript.md | 1 - change-notes/1.25/analysis-javascript.md | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 change-notes/1.25/analysis-javascript.md diff --git a/change-notes/1.24/analysis-javascript.md b/change-notes/1.24/analysis-javascript.md index bba72368168..0e92d66033d 100644 --- a/change-notes/1.24/analysis-javascript.md +++ b/change-notes/1.24/analysis-javascript.md @@ -87,7 +87,6 @@ | Identical operands (`js/redundant-operation`) | Fewer results | This query now recognizes cases where the operands change a value using ++/-- expressions. | | Superfluous trailing arguments (`js/superfluous-trailing-arguments`) | Fewer results | This query now recognizes cases where a function uses the `Function.arguments` value to process a variable number of parameters. | | Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes more variations of URL scheme checks. | -| Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. | ## Changes to libraries diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md new file mode 100644 index 00000000000..ee1c3c8ee3e --- /dev/null +++ b/change-notes/1.25/analysis-javascript.md @@ -0,0 +1,20 @@ +# Improvements to JavaScript analysis + +## General improvements + + +## New queries + +| **Query** | **Tags** | **Purpose** | +|---------------------------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| + + +## Changes to existing queries + +| **Query** | **Expected impact** | **Change** | +|--------------------------------|------------------------------|---------------------------------------------------------------------------| +| Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. | + +## Changes to libraries + + From cffa9116618cd0786fce4c42c3bc935f817aaa43 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 17 Apr 2020 14:22:57 +0200 Subject: [PATCH 0188/1298] retarget change note for 1.25 --- change-notes/1.24/analysis-javascript.md | 2 -- change-notes/1.25/analysis-javascript.md | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 change-notes/1.25/analysis-javascript.md diff --git a/change-notes/1.24/analysis-javascript.md b/change-notes/1.24/analysis-javascript.md index e3f7e920848..c27f7850041 100644 --- a/change-notes/1.24/analysis-javascript.md +++ b/change-notes/1.24/analysis-javascript.md @@ -87,8 +87,6 @@ | Identical operands (`js/redundant-operation`) | Fewer results | This query now recognizes cases where the operands change a value using ++/-- expressions. | | Superfluous trailing arguments (`js/superfluous-trailing-arguments`) | Fewer results | This query now recognizes cases where a function uses the `Function.arguments` value to process a variable number of parameters. | | Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional variations of URL scheme checks. | -| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. | -| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. | ## Changes to libraries diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md new file mode 100644 index 00000000000..e26ed8fee6f --- /dev/null +++ b/change-notes/1.25/analysis-javascript.md @@ -0,0 +1,22 @@ +# Improvements to JavaScript analysis + +## General improvements + + +## New queries + +| **Query** | **Tags** | **Purpose** | +|---------------------------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| + + +## Changes to existing queries + +| **Query** | **Expected impact** | **Change** | +|--------------------------------|------------------------------|---------------------------------------------------------------------------| +| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. | +| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. | + +## Changes to libraries + + + From c1323886b61cfcb9bd06c0d068c4a207cb859023 Mon Sep 17 00:00:00 2001 From: Felicity Chapman Date: Fri, 17 Apr 2020 13:30:49 +0100 Subject: [PATCH 0189/1298] Update change-notes/1.24/analysis-javascript.md Co-Authored-By: Esben Sparre Andreasen --- change-notes/1.24/analysis-javascript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.24/analysis-javascript.md b/change-notes/1.24/analysis-javascript.md index 0c2172bac7a..ee776a61acb 100644 --- a/change-notes/1.24/analysis-javascript.md +++ b/change-notes/1.24/analysis-javascript.md @@ -78,7 +78,7 @@ | Expression has no effect (`js/useless-expression`) | Fewer false positive results | The query now recognizes block-level flow type annotations and ignores the first statement of a try block. | | Identical operands (`js/redundant-operation`) | Fewer results | This query now excludes cases where the operands change a value using ++/-- expressions. | | Incomplete string escaping or encoding (`js/incomplete-sanitization`) | Fewer false positive results | This query now recognizes and excludes additional cases where a single replacement is likely to be intentional. | -| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes more variations of URL scheme checks. | +| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional variations of URL scheme checks. | | Missing CSRF middleware (`js/missing-token-validation`) | Fewer false positive results | The query reports fewer duplicates and only flags handlers that explicitly access cookie data. | | Superfluous trailing arguments (`js/superfluous-trailing-arguments`) | Fewer results | This query now excludes cases where a function uses the `Function.arguments` value to process a variable number of parameters. | | Syntax error (`js/syntax-error`) | Lower severity | This results of this query are now displayed with lower severity. | From d5145d9f0a8db7c2e36c079c3bb83eff25253724 Mon Sep 17 00:00:00 2001 From: Felicity Chapman Date: Fri, 17 Apr 2020 14:05:21 +0100 Subject: [PATCH 0190/1298] Sort table alphabetically --- change-notes/1.24/analysis-cpp.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/change-notes/1.24/analysis-cpp.md b/change-notes/1.24/analysis-cpp.md index b9a7cdc96a0..63b5ffb9022 100644 --- a/change-notes/1.24/analysis-cpp.md +++ b/change-notes/1.24/analysis-cpp.md @@ -14,24 +14,23 @@ The following changes in version 1.24 affect C/C++ analysis in all applications. | **Query** | **Expected impact** | **Change** | |----------------------------|------------------------|------------------------------------------------------------------| +| All CWE-specific queries using taint tracking (`cpp/path-injection`, `cpp/cgi-xss`, `cpp/sql-injection`, `cpp/uncontrolled-process-operation`, `cpp/unbounded-write`, `cpp/tainted-format-string`, `cpp/tainted-format-string-through-global`, `cpp/uncontrolled-arithmetic`, `cpp/uncontrolled-allocation-size`, `cpp/user-controlled-bypass`, `cpp/cleartext-storage-buffer`, `cpp/tainted-permissions-check`) | More correct results | A new taint-tracking library is used, giving more precise results and offering _path explanations_ for results. There is a performance cost to this, and the LGTM suite will overall run slower than before. | +| Boost\_asio TLS Settings Misconfiguration (`cpp/boost/tls-settings-misconfiguration`) | Query id change | Query id renamed from `cpp/boost/tls_settings_misconfiguration` (underscores to dashes) | | Buffer not sufficient for string (`cpp/overflow-calculated`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. | -| No space for zero terminator (`cpp/no-space-for-terminator`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. | +| Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) | | This query is no longer run on LGTM. | | Memory is never freed (`cpp/memory-never-freed`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. | | Memory may not be freed (`cpp/memory-may-not-be-freed`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. | | Mismatching new/free or malloc/delete (`cpp/new-free-mismatch`) | Fewer false positive results | Fixed false positive results in template code. | | Missing return statement (`cpp/missing-return`) | Fewer false positive results | Functions containing `asm` statements are no longer highlighted by this query. | | Missing return statement (`cpp/missing-return`) | More accurate locations | Locations reported by this query are now more accurate in some cases. | | No space for zero terminator (`cpp/no-space-for-terminator`) | More correct results | String arguments to formatting functions are now (usually) expected to be null terminated strings. | -| Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) | | This query is no longer run on LGTM. | +| No space for zero terminator (`cpp/no-space-for-terminator`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. | | No space for zero terminator (`cpp/no-space-for-terminator`) | Fewer false positive results | This query has been modified to be more conservative when identifying which pointers point to null-terminated strings. This approach produces fewer, more accurate results. | | Overflow in uncontrolled allocation size (`cpp/uncontrolled-allocation-size`) | Fewer false positive results | The query now produces fewer, more accurate results. Cases where the tainted allocation size is range checked are more reliably excluded. | | Overloaded assignment does not return 'this' (`cpp/assignment-does-not-return-this`) | Fewer false positive results | This query no longer reports incorrect results in template classes. | -| Unsafe array for days of the year (`cpp/leap-year/unsafe-array-for-days-of-the-year`) | | This query is no longer run on LGTM. | -| Boost\_asio TLS Settings Misconfiguration (`cpp/boost/tls-settings-misconfiguration`) | Query id change | Query id renamed from `cpp/boost/tls_settings_misconfiguration` (underscores to dashes) | -| Unsigned comparison to zero (`cpp/unsigned-comparison-zero`) | More correct results | This query now also looks for comparisons of the form `0 <= x`. | | Signed overflow check (`cpp/signed-overflow-check`), Pointer overflow check (`cpp/pointer-overflow-check`), Possibly wrong buffer size in string copy (`cpp/bad-strncpy-size`) | More correct results | A new library is used for determining which expressions have identical value, giving more precise results. There is a performance cost to this, and the LGTM suite will overall run slower than before. | -| All CWE-specific queries using taint tracking (`cpp/path-injection`, `cpp/cgi-xss`, `cpp/sql-injection`, `cpp/uncontrolled-process-operation`, `cpp/unbounded-write`, `cpp/tainted-format-string`, `cpp/tainted-format-string-through-global`, `cpp/uncontrolled-arithmetic`, `cpp/uncontrolled-allocation-size`, `cpp/user-controlled-bypass`, `cpp/cleartext-storage-buffer`, `cpp/tainted-permissions-check`) | More correct results | A new taint-tracking library is used, giving more precise results and offering _path explanations_ for results. There is a performance cost to this, and the LGTM suite will overall run slower than before. | - +| Unsafe array for days of the year (`cpp/leap-year/unsafe-array-for-days-of-the-year`) | | This query is no longer run on LGTM. | +| Unsigned comparison to zero (`cpp/unsigned-comparison-zero`) | More correct results | This query now also looks for comparisons of the form `0 <= x`. | ## Changes to libraries From 05d0d844bdafb0ea686280576faf45b87cb4db69 Mon Sep 17 00:00:00 2001 From: Felicity Chapman Date: Fri, 17 Apr 2020 14:36:30 +0100 Subject: [PATCH 0191/1298] Editorial changes --- change-notes/1.24/analysis-cpp.md | 69 +++++++++++++++++-------------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/change-notes/1.24/analysis-cpp.md b/change-notes/1.24/analysis-cpp.md index 63b5ffb9022..b3553cdf84f 100644 --- a/change-notes/1.24/analysis-cpp.md +++ b/change-notes/1.24/analysis-cpp.md @@ -4,6 +4,8 @@ The following changes in version 1.24 affect C/C++ analysis in all applications. ## General improvements +You can now suppress alerts using either single-line block comments (`/* ... */`) or line comments (`// ...`). + ## New queries | **Query** | **Tags** | **Purpose** | @@ -12,23 +14,27 @@ The following changes in version 1.24 affect C/C++ analysis in all applications. ## Changes to existing queries +A new taint-tracking library is used by all the security queries that track tainted values +(`cpp/path-injection`, `cpp/cgi-xss`, `cpp/sql-injection`, `cpp/uncontrolled-process-operation`, +`cpp/unbounded-write`, `cpp/tainted-format-string`, `cpp/tainted-format-string-through-global`, +`cpp/uncontrolled-arithmetic`, `cpp/uncontrolled-allocation-size`, `cpp/user-controlled-bypass`, +`cpp/cleartext-storage-buffer`, `cpp/tainted-permissions-check`). +These queries now have more precise results and also offer _path explanations_ so you can explore the results easily. +There is a performance cost to this, and the LGTM query suite will overall run slower than before. + | **Query** | **Expected impact** | **Change** | |----------------------------|------------------------|------------------------------------------------------------------| -| All CWE-specific queries using taint tracking (`cpp/path-injection`, `cpp/cgi-xss`, `cpp/sql-injection`, `cpp/uncontrolled-process-operation`, `cpp/unbounded-write`, `cpp/tainted-format-string`, `cpp/tainted-format-string-through-global`, `cpp/uncontrolled-arithmetic`, `cpp/uncontrolled-allocation-size`, `cpp/user-controlled-bypass`, `cpp/cleartext-storage-buffer`, `cpp/tainted-permissions-check`) | More correct results | A new taint-tracking library is used, giving more precise results and offering _path explanations_ for results. There is a performance cost to this, and the LGTM suite will overall run slower than before. | -| Boost\_asio TLS Settings Misconfiguration (`cpp/boost/tls-settings-misconfiguration`) | Query id change | Query id renamed from `cpp/boost/tls_settings_misconfiguration` (underscores to dashes) | +| Boost\_asio TLS Settings Misconfiguration (`cpp/boost/tls-settings-misconfiguration`) | Query id change | The identifier was updated to use dashes in place of underscores (previous identifier `cpp/boost/tls_settings_misconfiguration`). | | Buffer not sufficient for string (`cpp/overflow-calculated`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. | | Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) | | This query is no longer run on LGTM. | | Memory is never freed (`cpp/memory-never-freed`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. | | Memory may not be freed (`cpp/memory-may-not-be-freed`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. | -| Mismatching new/free or malloc/delete (`cpp/new-free-mismatch`) | Fewer false positive results | Fixed false positive results in template code. | -| Missing return statement (`cpp/missing-return`) | Fewer false positive results | Functions containing `asm` statements are no longer highlighted by this query. | -| Missing return statement (`cpp/missing-return`) | More accurate locations | Locations reported by this query are now more accurate in some cases. | -| No space for zero terminator (`cpp/no-space-for-terminator`) | More correct results | String arguments to formatting functions are now (usually) expected to be null terminated strings. | -| No space for zero terminator (`cpp/no-space-for-terminator`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. | -| No space for zero terminator (`cpp/no-space-for-terminator`) | Fewer false positive results | This query has been modified to be more conservative when identifying which pointers point to null-terminated strings. This approach produces fewer, more accurate results. | +| Mismatching new/free or malloc/delete (`cpp/new-free-mismatch`) | Fewer false positive results | Improved handling of template code gives greater precision. | +| Missing return statement (`cpp/missing-return`) | Fewer false positive results and more accurate locations | Functions containing `asm` statements are no longer highlighted by this query. The locations reported by this query are now more accurate in some cases. | +| No space for zero terminator (`cpp/no-space-for-terminator`) | More results with greater precision | The query gives more precise results for a wider variety of buffer allocations. String arguments to formatting functions are now (usually) expected to be null terminated strings. Use of the `semmle.code.cpp.models.interfaces.Allocation` library identifies problems with a wider variety of buffer allocations. This query is also more conservative when identifying which pointers point to null-terminated strings. | | Overflow in uncontrolled allocation size (`cpp/uncontrolled-allocation-size`) | Fewer false positive results | The query now produces fewer, more accurate results. Cases where the tainted allocation size is range checked are more reliably excluded. | | Overloaded assignment does not return 'this' (`cpp/assignment-does-not-return-this`) | Fewer false positive results | This query no longer reports incorrect results in template classes. | -| Signed overflow check (`cpp/signed-overflow-check`), Pointer overflow check (`cpp/pointer-overflow-check`), Possibly wrong buffer size in string copy (`cpp/bad-strncpy-size`) | More correct results | A new library is used for determining which expressions have identical value, giving more precise results. There is a performance cost to this, and the LGTM suite will overall run slower than before. | +| Pointer overflow check (`cpp/pointer-overflow-check`),
    Possibly wrong buffer size in string copy (`cpp/bad-strncpy-size`),
    Signed overflow check (`cpp/signed-overflow-check`) | More correct results | A new library is used for determining which expressions have identical value, giving more precise results. There is a performance cost to this, and the LGTM suite will overall run slower than before. | | Unsafe array for days of the year (`cpp/leap-year/unsafe-array-for-days-of-the-year`) | | This query is no longer run on LGTM. | | Unsigned comparison to zero (`cpp/unsigned-comparison-zero`) | More correct results | This query now also looks for comparisons of the form `0 <= x`. | @@ -40,9 +46,9 @@ The following changes in version 1.24 affect C/C++ analysis in all applications. * The data-flow library (`semmle.code.cpp.dataflow.DataFlow` and `semmle.code.cpp.dataflow.TaintTracking`) has been improved, which affects and improves some security queries. The improvements are: - - Track flow through functions that combine taint tracking with flow through fields. - - Track flow through clone-like functions, that is, functions that read contents of a field from a - parameter and stores the value in the field of a returned object. + - Track flow through functions that combine taint tracking with flow through fields. + - Track flow through clone-like functions, that is, functions that read contents of a field from a + parameter and stores the value in the field of a returned object. * The security pack taint tracking library (`semmle.code.cpp.security.TaintTracking`) uses a new intermediate representation. This provides a more precise analysis of flow through @@ -52,28 +58,27 @@ The following changes in version 1.24 affect C/C++ analysis in all applications. (`semmle.code.cpp.valuenumbering.GlobalValueNumbering`) uses a new intermediate representation to provide a more precise analysis of heap-allocated memory and pointers to stack variables. -* Created the `semmle.code.cpp.models.interfaces.Allocation` library to model - allocation such as `new` expressions and calls to `malloc`. This in intended - to replace the functionality in `semmle.code.cpp.commons.Alloc` with a more - consistent and useful interface. - * The predicate `freeCall` in `semmle.code.cpp.commons.Alloc` has been - deprecated. The`Allocation` and `Deallocation` models in - `semmle.code.cpp.models.interfaces` should be used instead. - * Created the `semmle.code.cpp.models.interfaces.Deallocation` library to - model deallocation such as `delete` expressions and calls to `free`. This - in intended to replace the functionality in `semmle.code.cpp.commons.Alloc` - with a more consistent and useful interface. +* New libraries have been created to provide a more consistent and useful interface + for modeling allocation and deallocation. These replace the old + `semmle.code.cpp.commons.Alloc` library. + * The new `semmle.code.cpp.models.interfaces.Allocation` library models + allocations, such as `new` expressions and calls to `malloc`. + * The new `semmle.code.cpp.models.interfaces.Deallocation` library + models deallocations, such as `delete` expressions and calls to `free`. + * The predicate `freeCall` in `semmle.code.cpp.commons.Alloc` has been + deprecated. The `Allocation` and `Deallocation` models in + `semmle.code.cpp.models.interfaces` should be used instead. * The new class `StackVariable` should be used in place of `LocalScopeVariable` in most cases. The difference is that `StackVariable` does not include variables declared with `static` or `thread_local`. - * As a rule of thumb, custom queries about the _values_ of variables should - be changed from `LocalScopeVariable` to `StackVariable`, while queries - about the _name or scope_ of variables should remain unchanged. - * The `LocalScopeVariableReachability` library is deprecated in favor of - `StackVariableReachability`. The functionality is the same. + * As a rule of thumb, custom queries about the _values_ of variables should + be changed from `LocalScopeVariable` to `StackVariable`, while queries + about the _name or scope_ of variables should remain unchanged. + * The `LocalScopeVariableReachability` library is deprecated in favor of + `StackVariableReachability`. The functionality is the same. * Taint tracking and data flow now features better modeling of commonly-used library functions: - * `gets` and similar functions, - * the most common operations on `std::string`, - * `strdup` and similar functions, and - * formatting functions such as `sprintf`. + * `gets` and similar functions, + * the most common operations on `std::string`, + * `strdup` and similar functions, and + * formatting functions such as `sprintf`. From 01d3257d72d4ab00357b58ac5c2e05786a568ae8 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 17 Apr 2020 17:01:58 +0100 Subject: [PATCH 0192/1298] C++: Add test cases involving casts. --- .../ComparisonWithWiderType.expected | 3 ++ .../semmle/ComparisonWithWiderType/test.c | 31 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/ComparisonWithWiderType.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/ComparisonWithWiderType.expected index a822d1dfbf6..5202378bbaf 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/ComparisonWithWiderType.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/ComparisonWithWiderType.expected @@ -11,3 +11,6 @@ | test.c:103:14:103:33 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:103:19:103:32 | ... & ... | ... & ... | | test.c:105:14:105:25 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:105:19:105:24 | ... >> ... | ... >> ... | | test.c:107:14:107:26 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:107:19:107:25 | ... >> ... | ... >> ... | +| test.c:128:15:128:21 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:121:16:121:17 | uc | uc | test.c:123:19:123:20 | sz | sz | +| test.c:139:15:139:21 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:121:16:121:17 | uc | uc | test.c:123:19:123:20 | sz | sz | +| test.c:146:15:146:21 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:121:16:121:17 | uc | uc | test.c:123:19:123:20 | sz | sz | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test.c b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test.c index c33b28a1a76..05bcea356d4 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test.c @@ -114,3 +114,34 @@ void test12() { x = get_a_uint(); for (c = 0; c < ((x & 0xFF000000) >> 24); c++) {} // GOOD } + +int get_an_int(); + +void test13() { + unsigned char uc; + int sx, sy; + unsigned ux, uy, sz; + + ux = get_a_uint(); + uy = get_a_uint(); + sz = ux & uy; + for (uc = 0; uc < sz; uc++) {} // BAD + + ux = get_a_uint(); + uy = get_a_uint(); + if (ux > 128) {ux = 128;} + sz = ux & uy; + for (uc = 0; uc < sz; uc++) {} // GOOD + + sx = get_an_int(); + sy = get_an_int(); + sz = (unsigned)sx & (unsigned)sy; + for (uc = 0; uc < sz; uc++) {} // BAD + + sx = get_an_int(); + sy = get_an_int(); + if (sx < 0) {sx = 0;} + if (sx > 128) {sx = 128;} + sz = (unsigned)sx & (unsigned)sy; + for (uc = 0; uc < sz; uc++) {} // GOOD [FALSE POSITIVE] +} From de751b0b75dac5cb5e7f497e4672ec500ca966f6 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 17 Apr 2020 17:10:59 +0100 Subject: [PATCH 0193/1298] C++: Correct UnsignedBitwiseAndExpr. --- .../src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll | 4 ++-- .../ComparisonWithWiderType/ComparisonWithWiderType.expected | 1 - .../CWE/CWE-190/semmle/ComparisonWithWiderType/test.c | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll index bf592dcfbe7..4e3e83d4cc2 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll @@ -125,11 +125,11 @@ private string getValue(Expr e) { private class UnsignedBitwiseAndExpr extends BitwiseAndExpr { UnsignedBitwiseAndExpr() { ( - getLeftOperand().getType().getUnderlyingType().(IntegralType).isUnsigned() or + getLeftOperand().getFullyConverted().getType().getUnderlyingType().(IntegralType).isUnsigned() or getLeftOperand().getValue().toInt() >= 0 ) and ( - getRightOperand().getType().getUnderlyingType().(IntegralType).isUnsigned() or + getRightOperand().getFullyConverted().getType().getUnderlyingType().(IntegralType).isUnsigned() or getRightOperand().getValue().toInt() >= 0 ) } diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/ComparisonWithWiderType.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/ComparisonWithWiderType.expected index 5202378bbaf..d04bff0a812 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/ComparisonWithWiderType.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/ComparisonWithWiderType.expected @@ -13,4 +13,3 @@ | test.c:107:14:107:26 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:107:19:107:25 | ... >> ... | ... >> ... | | test.c:128:15:128:21 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:121:16:121:17 | uc | uc | test.c:123:19:123:20 | sz | sz | | test.c:139:15:139:21 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:121:16:121:17 | uc | uc | test.c:123:19:123:20 | sz | sz | -| test.c:146:15:146:21 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:121:16:121:17 | uc | uc | test.c:123:19:123:20 | sz | sz | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test.c b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test.c index 05bcea356d4..f0b7f445aeb 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test.c @@ -143,5 +143,5 @@ void test13() { if (sx < 0) {sx = 0;} if (sx > 128) {sx = 128;} sz = (unsigned)sx & (unsigned)sy; - for (uc = 0; uc < sz; uc++) {} // GOOD [FALSE POSITIVE] + for (uc = 0; uc < sz; uc++) {} // GOOD } From a7c22db989d8643fc1273d2ffda88a71cc32b5a7 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 17 Apr 2020 18:50:41 +0100 Subject: [PATCH 0194/1298] C++: Autoformat. --- .../semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll index 4e3e83d4cc2..03be750ac02 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll @@ -129,7 +129,12 @@ private class UnsignedBitwiseAndExpr extends BitwiseAndExpr { getLeftOperand().getValue().toInt() >= 0 ) and ( - getRightOperand().getFullyConverted().getType().getUnderlyingType().(IntegralType).isUnsigned() or + getRightOperand() + .getFullyConverted() + .getType() + .getUnderlyingType() + .(IntegralType) + .isUnsigned() or getRightOperand().getValue().toInt() >= 0 ) } From af48bc3e57dd71ae009065d9525bd24b42b288e5 Mon Sep 17 00:00:00 2001 From: Grzegorz Golawski Date: Fri, 17 Apr 2020 21:45:42 +0200 Subject: [PATCH 0195/1298] CodeQL query to detect JNDI injections --- .../Security/CWE/CWE-074/JndiInjection.java | 21 ++++ .../Security/CWE/CWE-074/JndiInjection.qhelp | 36 ++++++ .../Security/CWE/CWE-074/JndiInjection.ql | 21 ++++ .../Security/CWE/CWE-074/JndiInjectionLib.qll | 91 ++++++++++++++ java/ql/src/experimental/qlpack.yml | 4 + .../semmle/code/java/frameworks/Jndi.qll | 11 ++ .../semmle/code/java/frameworks/Shiro.qll | 6 + .../java/frameworks/spring/SpringJndi.qll | 6 + java/ql/test/experimental/qlpack.yml | 4 + .../security/CWE-074/JndiInjection.expected | 116 ++++++++++++++++++ .../security/CWE-074/JndiInjection.java | 78 ++++++++++++ .../security/CWE-074/JndiInjection.qlref | 1 + .../query-tests/security/CWE-074/options | 1 + .../org/apache/shiro/jndi/JndiTemplate.java | 13 ++ .../springframework/jndi/JndiTemplate.java | 14 +++ .../web/bind/annotation/RequestParam.java | 8 ++ 16 files changed, 431 insertions(+) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll create mode 100644 java/ql/src/experimental/qlpack.yml create mode 100644 java/ql/src/experimental/semmle/code/java/frameworks/Jndi.qll create mode 100644 java/ql/src/experimental/semmle/code/java/frameworks/Shiro.qll create mode 100644 java/ql/src/experimental/semmle/code/java/frameworks/spring/SpringJndi.qll create mode 100644 java/ql/test/experimental/qlpack.yml create mode 100644 java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-074/options create mode 100644 java/ql/test/experimental/stubs/shiro-core-1.5.2/org/apache/shiro/jndi/JndiTemplate.java create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/jndi/JndiTemplate.java create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestParam.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.java b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.java new file mode 100644 index 00000000000..ce75fdab6be --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.java @@ -0,0 +1,21 @@ +import javax.naming.Context; +import javax.naming.InitialContext; + +public void jndiLookup(HttpServletRequest request) throws NamingException { + String name = request.getParameter("name"); + + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); + env.put(Context.PROVIDER_URL, "rmi://trusted-server:1099"); + InitialContext ctx = new InitialContext(env); + + // BAD: User input used in lookup + ctx.lookup(name); + + // GOOD: The name is validated before being used in lookup + if (isValid(name)) { + ctx.lookup(name); + } else { + // Reject the request + } +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.qhelp new file mode 100644 index 00000000000..d1d7b2ba51f --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.qhelp @@ -0,0 +1,36 @@ + + + +

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

    +
    + + +

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

    +
    + + +

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

    + +

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

    + +

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

    + + +
    + + +
  • Oracle: Java Naming and Directory Interface (JNDI).
  • +
  • Black Hat materials: A Journey from JNDI/LDAP Manipulation to Remote Code Execution Dream Land.
  • +
  • Veracode: Exploiting JNDI Injections in Java.
  • + + diff --git a/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.ql new file mode 100644 index 00000000000..2b1af37dcae --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.ql @@ -0,0 +1,21 @@ +/** + * @name JNDI lookup with user-controlled name + * @description Doing a JNDI lookup with user-controlled name can lead to download an untrusted + * object and to execution of arbitrary code. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/jndi-injection + * @tags security + * external/cwe/cwe-074 + */ + +import java +import semmle.code.java.dataflow.FlowSources +import JndiInjectionLib +import DataFlow::PathGraph + +from DataFlow::PathNode source, DataFlow::PathNode sink, JndiInjectionFlowConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "JNDI lookup might include name from $@.", source.getNode(), + "this user input" diff --git a/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll new file mode 100644 index 00000000000..e8117d67c5e --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll @@ -0,0 +1,91 @@ +import java +import semmle.code.java.dataflow.FlowSources +import DataFlow +import experimental.semmle.code.java.frameworks.Jndi +import experimental.semmle.code.java.frameworks.spring.SpringJndi +import experimental.semmle.code.java.frameworks.Shiro + +/** + * A taint-tracking configuration for unvalidated user input that is used in JNDI lookup. + */ +class JndiInjectionFlowConfig extends TaintTracking::Configuration { + JndiInjectionFlowConfig() { this = "JndiInjectionFlowConfig" } + + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { sink instanceof JndiInjectionSink } + + override predicate isSanitizer(DataFlow::Node node) { + node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType + } + + override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { + compositeNameStep(node1, node2) + } +} + +/** + * JNDI sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup`, `lookupLink`, + * `doLookup`, `rename`, `list` or `listBindings` method from `InitialContext`. + */ +predicate jndiSinkMethod(Method m, int index) { + m.getDeclaringType().getAnAncestor() instanceof TypeInitialContext and + ( + m.hasName("lookup") or + m.hasName("lookupLink") or + m.hasName("doLookup") or + m.hasName("rename") or + m.hasName("list") or + m.hasName("listBindings") + ) and + index = 0 +} + +/** + * Spring sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup` method from + * Spring's `JndiTemplate`. + */ +predicate springSinkMethod(Method m, int index) { + m.getDeclaringType() instanceof TypeSpringJndiTemplate and + m.hasName("lookup") and + index = 0 +} + +/** + * Apache Shiro sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup` method from + * Shiro's `JndiTemplate`. + */ +predicate shiroSinkMethod(Method m, int index) { + m.getDeclaringType() instanceof TypeShiroJndiTemplate and + m.hasName("lookup") and + index = 0 +} + +/** Holds if parameter at index `index` in method `m` is JNDI injection sink. */ +predicate jndiInjectionSinkMethod(Method m, int index) { + jndiSinkMethod(m, index) or + springSinkMethod(m, index) or + shiroSinkMethod(m, index) +} + +/** A data flow sink for unvalidated user input that is used in JNDI lookup. */ +class JndiInjectionSink extends DataFlow::ExprNode { + JndiInjectionSink() { + exists(MethodAccess ma, Method m, int index | + ma.getMethod() = m and + ma.getArgument(index) = this.getExpr() and + jndiInjectionSinkMethod(m, index) + ) + } +} + +/** + * Holds if `n1` to `n2` is a dataflow step that converts between `String` and `CompositeName`, + * i.e. `new CompositeName(tainted)`. + */ +predicate compositeNameStep(ExprNode n1, ExprNode n2) { + exists(ConstructorCall cc | cc.getConstructedType() instanceof TypeCompositeName | + n1.asExpr() = cc.getAnArgument() and + n2.asExpr() = cc + ) +} diff --git a/java/ql/src/experimental/qlpack.yml b/java/ql/src/experimental/qlpack.yml new file mode 100644 index 00000000000..bf76fc1b736 --- /dev/null +++ b/java/ql/src/experimental/qlpack.yml @@ -0,0 +1,4 @@ +name: codeql-java-experimental +version: 0.0.0 +libraryPathDependencies: codeql-java +extractor: java diff --git a/java/ql/src/experimental/semmle/code/java/frameworks/Jndi.qll b/java/ql/src/experimental/semmle/code/java/frameworks/Jndi.qll new file mode 100644 index 00000000000..bf2ff44bc06 --- /dev/null +++ b/java/ql/src/experimental/semmle/code/java/frameworks/Jndi.qll @@ -0,0 +1,11 @@ +import java + +/** The class `javax.naming.InitialContext`. */ +class TypeInitialContext extends Class { + TypeInitialContext() { this.hasQualifiedName("javax.naming", "InitialContext") } +} + +/** The class `javax.naming.CompositeName`. */ +class TypeCompositeName extends Class { + TypeCompositeName() { this.hasQualifiedName("javax.naming", "CompositeName") } +} diff --git a/java/ql/src/experimental/semmle/code/java/frameworks/Shiro.qll b/java/ql/src/experimental/semmle/code/java/frameworks/Shiro.qll new file mode 100644 index 00000000000..55e42f14fcf --- /dev/null +++ b/java/ql/src/experimental/semmle/code/java/frameworks/Shiro.qll @@ -0,0 +1,6 @@ +import java + +/** The class `org.apache.shiro.jndi.JndiTemplate`. */ +class TypeShiroJndiTemplate extends Class { + TypeShiroJndiTemplate() { this.hasQualifiedName("org.apache.shiro.jndi", "JndiTemplate") } +} diff --git a/java/ql/src/experimental/semmle/code/java/frameworks/spring/SpringJndi.qll b/java/ql/src/experimental/semmle/code/java/frameworks/spring/SpringJndi.qll new file mode 100644 index 00000000000..6033e359b17 --- /dev/null +++ b/java/ql/src/experimental/semmle/code/java/frameworks/spring/SpringJndi.qll @@ -0,0 +1,6 @@ +import java + +/** The class `org.springframework.jndi.JndiTemplate`. */ +class TypeSpringJndiTemplate extends Class { + TypeSpringJndiTemplate() { this.hasQualifiedName("org.springframework.jndi", "JndiTemplate") } +} diff --git a/java/ql/test/experimental/qlpack.yml b/java/ql/test/experimental/qlpack.yml new file mode 100644 index 00000000000..4b7a7635a6c --- /dev/null +++ b/java/ql/test/experimental/qlpack.yml @@ -0,0 +1,4 @@ +name: codeql-java-experimental-tests +version: 0.0.0 +libraryPathDependencies: codeql-java-experimental +extractor: java diff --git a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected new file mode 100644 index 00000000000..5aceacc53d3 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected @@ -0,0 +1,116 @@ +edges +| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:16:16:16:22 | nameStr | +| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:17:20:17:26 | nameStr | +| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:18:29:18:35 | nameStr | +| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:19:16:19:22 | nameStr | +| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:20:14:20:20 | nameStr | +| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:21:22:21:28 | nameStr | +| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:23:16:23:19 | name | +| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:24:20:24:23 | name | +| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:25:29:25:32 | name | +| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:26:16:26:19 | name | +| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:27:14:27:17 | name | +| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:28:22:28:25 | name | +| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:35:16:35:22 | nameStr | +| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:36:20:36:26 | nameStr | +| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:37:16:37:22 | nameStr | +| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:38:14:38:20 | nameStr | +| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:39:22:39:28 | nameStr | +| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:41:16:41:19 | name | +| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:42:20:42:23 | name | +| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:43:16:43:19 | name | +| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:44:14:44:17 | name | +| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:45:22:45:25 | name | +| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:52:16:52:22 | nameStr | +| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:53:20:53:26 | nameStr | +| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:54:16:54:22 | nameStr | +| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:55:14:55:20 | nameStr | +| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:56:22:56:28 | nameStr | +| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:58:16:58:19 | name | +| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:59:20:59:23 | name | +| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:60:16:60:19 | name | +| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:61:14:61:17 | name | +| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:62:22:62:25 | name | +| JndiInjection.java:65:42:65:69 | nameStr : String | JndiInjection.java:68:16:68:22 | nameStr | +| JndiInjection.java:65:42:65:69 | nameStr : String | JndiInjection.java:69:16:69:22 | nameStr | +| JndiInjection.java:72:41:72:68 | nameStr : String | JndiInjection.java:75:16:75:22 | nameStr | +| JndiInjection.java:72:41:72:68 | nameStr : String | JndiInjection.java:76:16:76:22 | nameStr | +nodes +| JndiInjection.java:12:38:12:65 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:16:16:16:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:17:20:17:26 | nameStr | semmle.label | nameStr | +| JndiInjection.java:18:29:18:35 | nameStr | semmle.label | nameStr | +| JndiInjection.java:19:16:19:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:20:14:20:20 | nameStr | semmle.label | nameStr | +| JndiInjection.java:21:22:21:28 | nameStr | semmle.label | nameStr | +| JndiInjection.java:23:16:23:19 | name | semmle.label | name | +| JndiInjection.java:24:20:24:23 | name | semmle.label | name | +| JndiInjection.java:25:29:25:32 | name | semmle.label | name | +| JndiInjection.java:26:16:26:19 | name | semmle.label | name | +| JndiInjection.java:27:14:27:17 | name | semmle.label | name | +| JndiInjection.java:28:22:28:25 | name | semmle.label | name | +| JndiInjection.java:31:41:31:68 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:35:16:35:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:36:20:36:26 | nameStr | semmle.label | nameStr | +| JndiInjection.java:37:16:37:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:38:14:38:20 | nameStr | semmle.label | nameStr | +| JndiInjection.java:39:22:39:28 | nameStr | semmle.label | nameStr | +| JndiInjection.java:41:16:41:19 | name | semmle.label | name | +| JndiInjection.java:42:20:42:23 | name | semmle.label | name | +| JndiInjection.java:43:16:43:19 | name | semmle.label | name | +| JndiInjection.java:44:14:44:17 | name | semmle.label | name | +| JndiInjection.java:45:22:45:25 | name | semmle.label | name | +| JndiInjection.java:48:42:48:69 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:52:16:52:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:53:20:53:26 | nameStr | semmle.label | nameStr | +| JndiInjection.java:54:16:54:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:55:14:55:20 | nameStr | semmle.label | nameStr | +| JndiInjection.java:56:22:56:28 | nameStr | semmle.label | nameStr | +| JndiInjection.java:58:16:58:19 | name | semmle.label | name | +| JndiInjection.java:59:20:59:23 | name | semmle.label | name | +| JndiInjection.java:60:16:60:19 | name | semmle.label | name | +| JndiInjection.java:61:14:61:17 | name | semmle.label | name | +| JndiInjection.java:62:22:62:25 | name | semmle.label | name | +| JndiInjection.java:65:42:65:69 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:68:16:68:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:69:16:69:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:72:41:72:68 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:75:16:75:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:76:16:76:22 | nameStr | semmle.label | nameStr | +#select +| JndiInjection.java:16:16:16:22 | nameStr | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:16:16:16:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | +| JndiInjection.java:17:20:17:26 | nameStr | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:17:20:17:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | +| JndiInjection.java:18:29:18:35 | nameStr | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:18:29:18:35 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | +| JndiInjection.java:19:16:19:22 | nameStr | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:19:16:19:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | +| JndiInjection.java:20:14:20:20 | nameStr | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:20:14:20:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | +| JndiInjection.java:21:22:21:28 | nameStr | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:21:22:21:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | +| JndiInjection.java:23:16:23:19 | name | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:23:16:23:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | +| JndiInjection.java:24:20:24:23 | name | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:24:20:24:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | +| JndiInjection.java:25:29:25:32 | name | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:25:29:25:32 | name | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | +| JndiInjection.java:26:16:26:19 | name | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:26:16:26:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | +| JndiInjection.java:27:14:27:17 | name | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:27:14:27:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | +| JndiInjection.java:28:22:28:25 | name | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:28:22:28:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | +| JndiInjection.java:35:16:35:22 | nameStr | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:35:16:35:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | +| JndiInjection.java:36:20:36:26 | nameStr | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:36:20:36:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | +| JndiInjection.java:37:16:37:22 | nameStr | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:37:16:37:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | +| JndiInjection.java:38:14:38:20 | nameStr | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:38:14:38:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | +| JndiInjection.java:39:22:39:28 | nameStr | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:39:22:39:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | +| JndiInjection.java:41:16:41:19 | name | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:41:16:41:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | +| JndiInjection.java:42:20:42:23 | name | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:42:20:42:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | +| JndiInjection.java:43:16:43:19 | name | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:43:16:43:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | +| JndiInjection.java:44:14:44:17 | name | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:44:14:44:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | +| JndiInjection.java:45:22:45:25 | name | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:45:22:45:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | +| JndiInjection.java:52:16:52:22 | nameStr | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:52:16:52:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | +| JndiInjection.java:53:20:53:26 | nameStr | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:53:20:53:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | +| JndiInjection.java:54:16:54:22 | nameStr | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:54:16:54:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | +| JndiInjection.java:55:14:55:20 | nameStr | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:55:14:55:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | +| JndiInjection.java:56:22:56:28 | nameStr | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:56:22:56:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | +| JndiInjection.java:58:16:58:19 | name | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:58:16:58:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | +| JndiInjection.java:59:20:59:23 | name | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:59:20:59:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | +| JndiInjection.java:60:16:60:19 | name | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:60:16:60:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | +| JndiInjection.java:61:14:61:17 | name | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:61:14:61:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | +| JndiInjection.java:62:22:62:25 | name | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:62:22:62:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | +| JndiInjection.java:68:16:68:22 | nameStr | JndiInjection.java:65:42:65:69 | nameStr : String | JndiInjection.java:68:16:68:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:65:42:65:69 | nameStr | this user input | +| JndiInjection.java:69:16:69:22 | nameStr | JndiInjection.java:65:42:65:69 | nameStr : String | JndiInjection.java:69:16:69:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:65:42:65:69 | nameStr | this user input | +| JndiInjection.java:75:16:75:22 | nameStr | JndiInjection.java:72:41:72:68 | nameStr : String | JndiInjection.java:75:16:75:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:72:41:72:68 | nameStr | this user input | +| JndiInjection.java:76:16:76:22 | nameStr | JndiInjection.java:72:41:72:68 | nameStr : String | JndiInjection.java:76:16:76:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:72:41:72:68 | nameStr | this user input | diff --git a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java new file mode 100644 index 00000000000..b6194566584 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java @@ -0,0 +1,78 @@ +import javax.naming.CompositeName; +import javax.naming.InitialContext; +import javax.naming.Name; +import javax.naming.NamingException; +import javax.naming.directory.InitialDirContext; +import javax.naming.ldap.InitialLdapContext; + +import org.springframework.jndi.JndiTemplate; +import org.springframework.web.bind.annotation.RequestParam; + +public class JndiInjection { + public void testInitialContextBad1(@RequestParam String nameStr) throws NamingException { + Name name = new CompositeName(nameStr); + InitialContext ctx = new InitialContext(); + + ctx.lookup(nameStr); + ctx.lookupLink(nameStr); + InitialContext.doLookup(nameStr); + ctx.rename(nameStr, ""); + ctx.list(nameStr); + ctx.listBindings(nameStr); + + ctx.lookup(name); + ctx.lookupLink(name); + InitialContext.doLookup(name); + ctx.rename(name, null); + ctx.list(name); + ctx.listBindings(name); + } + + public void testInitialDirContextBad1(@RequestParam String nameStr) throws NamingException { + Name name = new CompositeName(nameStr); + InitialDirContext ctx = new InitialDirContext(); + + ctx.lookup(nameStr); + ctx.lookupLink(nameStr); + ctx.rename(nameStr, ""); + ctx.list(nameStr); + ctx.listBindings(nameStr); + + ctx.lookup(name); + ctx.lookupLink(name); + ctx.rename(name, null); + ctx.list(name); + ctx.listBindings(name); + } + + public void testInitialLdapContextBad1(@RequestParam String nameStr) throws NamingException { + Name name = new CompositeName(nameStr); + InitialLdapContext ctx = new InitialLdapContext(); + + ctx.lookup(nameStr); + ctx.lookupLink(nameStr); + ctx.rename(nameStr, ""); + ctx.list(nameStr); + ctx.listBindings(nameStr); + + ctx.lookup(name); + ctx.lookupLink(name); + ctx.rename(name, null); + ctx.list(name); + ctx.listBindings(name); + } + + public void testSpringJndiTemplateBad1(@RequestParam String nameStr) throws NamingException { + JndiTemplate ctx = new JndiTemplate(); + + ctx.lookup(nameStr); + ctx.lookup(nameStr, null); + } + + public void testShiroJndiTemplateBad1(@RequestParam String nameStr) throws NamingException { + org.apache.shiro.jndi.JndiTemplate ctx = new org.apache.shiro.jndi.JndiTemplate(); + + ctx.lookup(nameStr); + ctx.lookup(nameStr, null); + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.qlref new file mode 100644 index 00000000000..8510660a459 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-074/JndiInjection.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-074/options b/java/ql/test/experimental/query-tests/security/CWE-074/options new file mode 100644 index 00000000000..ee7404e1be4 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-074/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.2.3:${testdir}/../../../stubs/shiro-core-1.5.2 \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/shiro-core-1.5.2/org/apache/shiro/jndi/JndiTemplate.java b/java/ql/test/experimental/stubs/shiro-core-1.5.2/org/apache/shiro/jndi/JndiTemplate.java new file mode 100644 index 00000000000..936be2abf7c --- /dev/null +++ b/java/ql/test/experimental/stubs/shiro-core-1.5.2/org/apache/shiro/jndi/JndiTemplate.java @@ -0,0 +1,13 @@ +package org.apache.shiro.jndi; + +import javax.naming.NamingException; + +public class JndiTemplate { + public Object lookup(final String name) throws NamingException { + return new Object(); + } + + public Object lookup(String name, Class requiredType) throws NamingException { + return new Object(); + } +} \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/jndi/JndiTemplate.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/jndi/JndiTemplate.java new file mode 100644 index 00000000000..81e5e2fe488 --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/jndi/JndiTemplate.java @@ -0,0 +1,14 @@ +package org.springframework.jndi; + +import javax.naming.NamingException; + +public class JndiTemplate { + public Object lookup(final String name) throws NamingException { + return new Object(); + } + + @SuppressWarnings("unchecked") + public T lookup(String name, Class requiredType) throws NamingException { + return (T) new Object(); + } +} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestParam.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestParam.java new file mode 100644 index 00000000000..5ae52ad123f --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestParam.java @@ -0,0 +1,8 @@ +package org.springframework.web.bind.annotation; + +import java.lang.annotation.*; + +@Target(value=ElementType.PARAMETER) +@Retention(value=RetentionPolicy.RUNTIME) +@Documented +public @interface RequestParam { } From de5abdb29a15a9980764a2ad740aa30348bbeebe Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Sat, 18 Apr 2020 09:55:35 -0400 Subject: [PATCH 0196/1298] C++/C#: Add missing QLDoc --- cpp/ql/src/semmle/code/cpp/Type.qll | 1 + .../ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll | 1 + 2 files changed, 2 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/Type.qll b/cpp/ql/src/semmle/code/cpp/Type.qll index f6787d00e1a..56e18fa055e 100644 --- a/cpp/ql/src/semmle/code/cpp/Type.qll +++ b/cpp/ql/src/semmle/code/cpp/Type.qll @@ -707,6 +707,7 @@ private newtype TTypeDomain = * `ImaginaryDomain`. */ class TypeDomain extends TTypeDomain { + /** Gets a textual representation of this type domain. */ string toString() { none() } } 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 24870f5635a..2272257fb19 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll @@ -35,6 +35,7 @@ private newtype TTypeDomain = TRealDomain() * `ImaginaryDomain`. */ class TypeDomain extends TTypeDomain { + /** Gets a textual representation of this type domain. */ string toString() { none() } } From 8041b74f1cf04b111ebe99f99f3d46537e7638bc Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Sat, 18 Apr 2020 09:56:38 -0400 Subject: [PATCH 0197/1298] C++: Fix formatting --- .../semmle/code/cpp/ir/internal/CppType.qll | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) 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 42420f8f925..d297097abd9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll @@ -453,12 +453,19 @@ CppPRValueType getCanonicalUnsignedIntegerType(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 + if type instanceof DoubleType + then result = 4 + else + if type instanceof FloatType + then result = 3 + else + if type instanceof LongDoubleType + then result = 2 + else + // If we get this far, prefer non-extended-precision types. + if not type.isExtendedPrecision() + then result = 1 + else result = 0 } /** From bb9fea5a279bc3cebba36bb87251326091f3fab5 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Sun, 19 Apr 2020 21:12:02 +0100 Subject: [PATCH 0198/1298] JS: Refactor isAmbient computation --- javascript/ql/src/semmle/javascript/AST.qll | 58 +++++++++++++++++-- .../ql/src/semmle/javascript/Classes.qll | 6 -- .../src/semmle/javascript/ES2015Modules.qll | 15 ----- .../ql/src/semmle/javascript/Functions.qll | 2 - javascript/ql/src/semmle/javascript/Stmt.qll | 4 -- .../ql/src/semmle/javascript/TypeScript.qll | 14 ----- 6 files changed, 52 insertions(+), 47 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/AST.qll b/javascript/ql/src/semmle/javascript/AST.qll index 81bb64f272c..bac0b396fe8 100644 --- a/javascript/ql/src/semmle/javascript/AST.qll +++ b/javascript/ql/src/semmle/javascript/AST.qll @@ -125,6 +125,42 @@ class ASTNode extends @ast_node, Locatable { /** Holds if this syntactic entity belongs to an externs file. */ predicate inExternsFile() { getTopLevel().isExterns() } + /** + * Holds if this is an ambient node that is not a `TypeExpr` and is not inside a `.d.ts` file + * + * Since the overwhelming majority of ambient nodes are `TypeExpr` or inside `.d.ts` files, + * we avoid caching them. + */ + cached + private predicate isAmbientInternal() { + getParent().isAmbientInternal() + or + not isAmbientTopLevel(getTopLevel()) and + ( + this instanceof ExternalModuleDeclaration + or + this instanceof GlobalAugmentationDeclaration + or + this instanceof ExportAsNamespaceDeclaration + or + this instanceof TypeAliasDeclaration + or + this instanceof InterfaceDeclaration + or + hasDeclareKeyword(this) + or + hasTypeKeyword(this) + or + // An export such as `export declare function f()` should be seen as ambient. + hasDeclareKeyword(this.(ExportNamedDeclaration).getOperand()) + or + exists(Function f | + this = f and + not f.hasBody() + ) + ) + } + /** * Holds if this is part of an ambient declaration or type annotation in a TypeScript file. * @@ -134,7 +170,22 @@ class ASTNode extends @ast_node, Locatable { * The TypeScript compiler emits no code for ambient declarations, but they * can affect name resolution and type checking at compile-time. */ - predicate isAmbient() { getParent().isAmbient() } + pragma[inline] + predicate isAmbient() { + isAmbientInternal() + or + isAmbientTopLevel(getTopLevel()) + or + this instanceof TypeExpr + } +} + +/** + * Holds if the given file is a `.d.ts` file. + */ +cached +private predicate isAmbientTopLevel(TopLevel tl) { + tl.getFile().getBaseName().matches("%.d.ts") } /** @@ -197,11 +248,6 @@ class TopLevel extends @toplevel, StmtContainer { override ControlFlowNode getFirstControlFlowNode() { result = getEntry() } override string toString() { result = "" } - - override predicate isAmbient() { - getFile().getFileType().isTypeScript() and - getFile().getBaseName().matches("%.d.ts") - } } /** diff --git a/javascript/ql/src/semmle/javascript/Classes.qll b/javascript/ql/src/semmle/javascript/Classes.qll index e93e0565ce8..ca2ffd20bc4 100644 --- a/javascript/ql/src/semmle/javascript/Classes.qll +++ b/javascript/ql/src/semmle/javascript/Classes.qll @@ -1059,12 +1059,6 @@ class FieldDeclaration extends MemberDeclaration, @field { /** Holds if this is a TypeScript field marked as definitely assigned with the `!` operator. */ predicate hasDefiniteAssignmentAssertion() { hasDefiniteAssignmentAssertion(this) } - - override predicate isAmbient() { - hasDeclareKeyword(this) - or - getParent().isAmbient() - } } /** diff --git a/javascript/ql/src/semmle/javascript/ES2015Modules.qll b/javascript/ql/src/semmle/javascript/ES2015Modules.qll index df094df2952..256bbf70064 100644 --- a/javascript/ql/src/semmle/javascript/ES2015Modules.qll +++ b/javascript/ql/src/semmle/javascript/ES2015Modules.qll @@ -79,11 +79,6 @@ class ImportDeclaration extends Stmt, Import, @importdeclaration { /** Holds if this is declared with the `type` keyword, so it only imports types. */ predicate isTypeOnly() { hasTypeKeyword(this) } - - override predicate isAmbient() { - Stmt.super.isAmbient() or - isTypeOnly() - } } /** A literal path expression appearing in an `import` declaration. */ @@ -267,11 +262,6 @@ abstract class ExportDeclaration extends Stmt, @exportdeclaration { /** Holds if is declared with the `type` keyword, so only types are exported. */ predicate isTypeOnly() { hasTypeKeyword(this) } - - override predicate isAmbient() { - Stmt.super.isAmbient() or - isTypeOnly() - } } /** @@ -422,11 +412,6 @@ class ExportNamedDeclaration extends ExportDeclaration, @exportnameddeclaration /** Gets an export specifier of this declaration. */ ExportSpecifier getASpecifier() { result = getSpecifier(_) } - - override predicate isAmbient() { - // An export such as `export declare function f()` should be seen as ambient. - hasDeclareKeyword(getOperand()) or getParent().isAmbient() - } } /** diff --git a/javascript/ql/src/semmle/javascript/Functions.qll b/javascript/ql/src/semmle/javascript/Functions.qll index 719e094dfc0..5a915089697 100644 --- a/javascript/ql/src/semmle/javascript/Functions.qll +++ b/javascript/ql/src/semmle/javascript/Functions.qll @@ -397,8 +397,6 @@ class Function extends @function, Parameterized, TypeParameterized, StmtContaine */ predicate isAbstract() { exists(MethodDeclaration md | this = md.getBody() | md.isAbstract()) } - override predicate isAmbient() { getParent().isAmbient() or not hasBody() } - /** * Holds if this function cannot be invoked using `new` because it * is of the given `kind`. diff --git a/javascript/ql/src/semmle/javascript/Stmt.qll b/javascript/ql/src/semmle/javascript/Stmt.qll index 7ec69344aa7..6b3d6e35d32 100644 --- a/javascript/ql/src/semmle/javascript/Stmt.qll +++ b/javascript/ql/src/semmle/javascript/Stmt.qll @@ -54,8 +54,6 @@ class Stmt extends @stmt, ExprOrStmt, Documentable { getContainer().(Expr).getEnclosingStmt().nestedIn(outer) } - override predicate isAmbient() { hasDeclareKeyword(this) or getParent().isAmbient() } - /** * Gets the `try` statement with a catch block containing this statement without * crossing function boundaries or other `try ` statements with catch blocks. @@ -931,8 +929,6 @@ class DebuggerStmt extends @debuggerstmt, Stmt { */ class FunctionDeclStmt extends @functiondeclstmt, Stmt, Function { override Stmt getEnclosingStmt() { result = this } - - override predicate isAmbient() { Function.super.isAmbient() } } /** diff --git a/javascript/ql/src/semmle/javascript/TypeScript.qll b/javascript/ql/src/semmle/javascript/TypeScript.qll index c6497355763..0bf8ab2faf0 100644 --- a/javascript/ql/src/semmle/javascript/TypeScript.qll +++ b/javascript/ql/src/semmle/javascript/TypeScript.qll @@ -155,8 +155,6 @@ class ExternalModuleDeclaration extends Stmt, StmtContainer, @externalmoduledecl int getNumStmt() { result = count(getAStmt()) } override StmtContainer getEnclosingContainer() { result = this.getContainer() } - - override predicate isAmbient() { any() } } /** @@ -176,8 +174,6 @@ class GlobalAugmentationDeclaration extends Stmt, StmtContainer, @globalaugmenta int getNumStmt() { result = count(getAStmt()) } override StmtContainer getEnclosingContainer() { result = this.getContainer() } - - override predicate isAmbient() { any() } } /** A TypeScript "import-equals" declaration. */ @@ -237,8 +233,6 @@ class ExportAsNamespaceDeclaration extends Stmt, @exportasnamespacedeclaration { * Gets the `X` in `export as namespace X`. */ Identifier getIdentifier() { result = getChildExpr(0) } - - override predicate isAmbient() { any() } } /** @@ -259,8 +253,6 @@ class TypeAliasDeclaration extends @typealiasdeclaration, TypeParameterized, Stm override string describe() { result = "type alias " + getName() } - override predicate isAmbient() { any() } - /** * Gets the canonical name of the type being defined. */ @@ -286,8 +278,6 @@ class InterfaceDeclaration extends Stmt, InterfaceDefinition, @interfacedeclarat override StmtContainer getContainer() { result = Stmt.super.getContainer() } - override predicate isAmbient() { any() } - override string describe() { result = "interface " + getName() } /** @@ -533,8 +523,6 @@ class LocalNamespaceName extends @local_namespace_name, LexicalName { class TypeExpr extends ExprOrType, @typeexpr, TypeAnnotation { override string toString() { typeexprs(this, _, _, _, result) } - override predicate isAmbient() { any() } - /** * Gets the static type expressed by this type annotation. * @@ -1410,8 +1398,6 @@ class EnumDeclaration extends NamespaceDefinition, @enumdeclaration, AST::ValueN /** Holds if this enumeration is declared with the `const` keyword. */ predicate isConst() { isConstEnum(this) } - override predicate isAmbient() { hasDeclareKeyword(this) or getParent().isAmbient() } - override ControlFlowNode getFirstControlFlowNode() { result = getIdentifier() } } From 6fca23bc8bbb9650c3b893d769a674e87546daad Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 20 Apr 2020 08:50:31 +0200 Subject: [PATCH 0199/1298] C++: Demonstrate lack of flow through single-field structs --- .../library-tests/dataflow/fields/flow.expected | 10 ++++++++++ .../test/library-tests/dataflow/fields/simple.cpp | 14 ++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/cpp/ql/test/library-tests/dataflow/fields/flow.expected b/cpp/ql/test/library-tests/dataflow/fields/flow.expected index ca851dc8974..650b5dcc073 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/flow.expected @@ -221,6 +221,10 @@ edges | simple.cpp:48:9:48:9 | g [b_] | simple.cpp:26:15:26:15 | f [b_] | | simple.cpp:51:9:51:9 | h [a_] | simple.cpp:26:15:26:15 | f [a_] | | simple.cpp:51:9:51:9 | h [b_] | simple.cpp:26:15:26:15 | f [b_] | +| simple.cpp:65:5:65:5 | a [post update] [i] | simple.cpp:67:10:67:11 | a2 [i] | +| simple.cpp:65:5:65:22 | ... = ... | simple.cpp:65:5:65:5 | a [post update] [i] | +| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | ... = ... | +| simple.cpp:67:10:67:11 | a2 [i] | simple.cpp:67:13:67:13 | i | | struct_init.c:14:24:14:25 | ab [a] | struct_init.c:15:8:15:9 | ab [a] | | struct_init.c:15:8:15:9 | ab [a] | struct_init.c:15:12:15:12 | a | | struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:22:8:22:9 | ab [a] | @@ -504,6 +508,11 @@ nodes | simple.cpp:48:9:48:9 | g [b_] | semmle.label | g [b_] | | simple.cpp:51:9:51:9 | h [a_] | semmle.label | h [a_] | | simple.cpp:51:9:51:9 | h [b_] | semmle.label | h [b_] | +| simple.cpp:65:5:65:5 | a [post update] [i] | semmle.label | a [post update] [i] | +| simple.cpp:65:5:65:22 | ... = ... | semmle.label | ... = ... | +| simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | +| simple.cpp:67:10:67:11 | a2 [i] | semmle.label | a2 [i] | +| simple.cpp:67:13:67:13 | i | semmle.label | i | | struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] | | struct_init.c:15:8:15:9 | ab [a] | semmle.label | ab [a] | | struct_init.c:15:12:15:12 | a | semmle.label | a | @@ -580,6 +589,7 @@ nodes | simple.cpp:28:12:28:12 | call to a | simple.cpp:41:12:41:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:41:12:41:21 | call to user_input | call to user_input | | simple.cpp:29:12:29:12 | call to b | simple.cpp:40:12:40:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:40:12:40:21 | call to user_input | call to user_input | | simple.cpp:29:12:29:12 | call to b | simple.cpp:42:12:42:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:42:12:42:21 | call to user_input | call to user_input | +| simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp index 6f36fa6551d..64b6748d0d5 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -53,4 +53,18 @@ void foo() // Nothing should alert bar(i); } + +struct A +{ + int i; +}; + +void single_field_test() +{ + A a; + a.i = user_input(); + A a2 = a; + sink(a2.i); +} + } // namespace Simple From a6e619ce5b4235c809dca60b12c43043eaa80991 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 20 Apr 2020 08:52:46 +0200 Subject: [PATCH 0200/1298] C++: Add field flow through single-field structs and accept tests --- .../ir/dataflow/internal/DataFlowPrivate.qll | 26 ++++++++++++++----- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 22 ++++++++++++++++ .../fields/dataflow-ir-consistency.expected | 1 + .../dataflow/fields/ir-flow.expected | 8 ++++++ 4 files changed, 51 insertions(+), 6 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 51290bc3293..531fcdfd368 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -180,12 +180,16 @@ private class ArrayContent extends Content, TArrayContent { override Type getType() { none() } } -/** - * Holds if data can flow from `node1` to `node2` via an assignment to `f`. - * Thus, `node2` references an object with a field `f` that contains the - * value of `node1`. - */ -predicate storeStep(Node node1, Content f, PostUpdateNode node2) { +private predicate storeStepNoChi(Node node1, Content f, PostUpdateNode node2) { + exists(FieldAddressInstruction fa, StoreInstruction store | + store = node2.asInstruction() and + store.getDestinationAddress() = fa and + store.getSourceValue() = node1.asInstruction() and + f.(FieldContent).getField() = fa.getField() + ) +} + +private predicate storeStepChi(Node node1, Content f, PostUpdateNode node2) { exists(FieldAddressInstruction fa, StoreInstruction store | node1.asInstruction() = store and store.getDestinationAddress() = fa and @@ -194,6 +198,16 @@ predicate storeStep(Node node1, Content f, PostUpdateNode node2) { ) } +/** + * Holds if data can flow from `node1` to `node2` via an assignment to `f`. + * Thus, `node2` references an object with a field `f` that contains the + * value of `node1`. + */ +predicate storeStep(Node node1, Content f, PostUpdateNode node2) { + storeStepNoChi(node1, f, node2) or + storeStepChi(node1, f, node2) +} + /** * Holds if data can flow from `node1` to `node2` via a read of `f`. * Thus, `node1` references an object with a field `f` whose value ends up in 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 8b0ade838dd..ac0d7fa6ce3 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 @@ -270,6 +270,19 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() } } +private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNode { + override StoreInstruction instr; + + ExplicitSingleFieldStoreQualifierNode() { + exists(FieldAddressInstruction field | + field = instr.getDestinationAddress() and + not exists(ChiInstruction chi | chi.getPartial() = instr) + ) + } + + override Node getPreUpdateNode() { none() } +} + /** * 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. @@ -404,6 +417,8 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction()) } +private predicate hasSize(Type t, int size) { t.getSize() = size } + cached private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction iTo) { iTo.(CopyInstruction).getSourceValue() = iFrom @@ -452,6 +467,13 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = chi ) or + iTo.(CopyInstruction).getSourceValueOperand().getAnyDef() = iFrom and + exists(Class c, int size | + c = iTo.getResultType() and + hasSize(c, size) and + hasSize(iFrom.getResultType(), size) + ) + or // Flow through modeled functions modelFlow(iFrom, iTo) } diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected index 1714355138c..227023fda16 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected @@ -19,6 +19,7 @@ unreachableNodeCCtx localCallNodes postIsNotPre postHasUniquePre +| simple.cpp:65:5:65:22 | Store | PostUpdateNode should have one pre-update node but has 0. | uniquePostUpdate postIsInSameCallable reverseRead diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected index 7a6432e29f3..4286d556cb9 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected @@ -25,6 +25,9 @@ edges | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | +| simple.cpp:65:5:65:22 | Store [i] | simple.cpp:66:12:66:12 | Store [i] | +| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | Store [i] | +| simple.cpp:66:12:66:12 | Store [i] | simple.cpp:67:13:67:13 | i | | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | nodes @@ -63,6 +66,10 @@ nodes | aliasing.cpp:87:12:87:13 | m1 | semmle.label | m1 | | aliasing.cpp:92:12:92:21 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 | +| simple.cpp:65:5:65:22 | Store [i] | semmle.label | Store [i] | +| simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | +| simple.cpp:66:12:66:12 | Store [i] | semmle.label | Store [i] | +| simple.cpp:67:13:67:13 | i | semmle.label | i | | struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input | | struct_init.c:22:11:22:11 | a | semmle.label | a | | struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input | @@ -78,5 +85,6 @@ nodes | aliasing.cpp:80:12:80:13 | m1 | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | m1 flows from $@ | aliasing.cpp:79:11:79:20 | call to user_input | call to user_input | | aliasing.cpp:87:12:87:13 | m1 | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | m1 flows from $@ | aliasing.cpp:86:10:86:19 | call to user_input | call to user_input | | aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input | call to user_input | +| simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | | struct_init.c:22:11:22:11 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | | struct_init.c:31:23:31:23 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | From 161093bd57f1e5f4b0066a663c46b5575f8823d1 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 20 Apr 2020 09:20:42 +0200 Subject: [PATCH 0201/1298] C#: Rename `arrays` data-flow test to `collections` --- .../dataflow/arrays/ArrayFlow.expected | 235 ------------------ .../CollectionFlow.cs} | 0 .../collections/CollectionFlow.expected | 235 ++++++++++++++++++ .../CollectionFlow.ql} | 0 4 files changed, 235 insertions(+), 235 deletions(-) delete mode 100644 csharp/ql/test/library-tests/dataflow/arrays/ArrayFlow.expected rename csharp/ql/test/library-tests/dataflow/{arrays/ArrayFlow.cs => collections/CollectionFlow.cs} (100%) create mode 100644 csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected rename csharp/ql/test/library-tests/dataflow/{arrays/ArrayFlow.ql => collections/CollectionFlow.ql} (100%) diff --git a/csharp/ql/test/library-tests/dataflow/arrays/ArrayFlow.expected b/csharp/ql/test/library-tests/dataflow/arrays/ArrayFlow.expected deleted file mode 100644 index 9a0b41ef207..00000000000 --- a/csharp/ql/test/library-tests/dataflow/arrays/ArrayFlow.expected +++ /dev/null @@ -1,235 +0,0 @@ -edges -| ArrayFlow.cs:10:17:10:23 | object creation of type A : A | ArrayFlow.cs:12:14:12:19 | access to array element | -| ArrayFlow.cs:10:17:10:23 | object creation of type A : A | ArrayFlow.cs:13:18:13:20 | access to local variable as : A[] | -| ArrayFlow.cs:10:17:10:23 | object creation of type A : A | ArrayFlow.cs:14:20:14:22 | access to local variable as : A[] | -| ArrayFlow.cs:13:18:13:20 | access to local variable as : A[] | ArrayFlow.cs:208:40:208:41 | ts : A[] | -| ArrayFlow.cs:14:20:14:22 | access to local variable as : A[] | ArrayFlow.cs:14:14:14:23 | call to method First | -| ArrayFlow.cs:28:17:28:23 | object creation of type A : A | ArrayFlow.cs:31:14:31:19 | access to array element | -| ArrayFlow.cs:28:17:28:23 | object creation of type A : A | ArrayFlow.cs:32:18:32:20 | access to local variable as : A[] | -| ArrayFlow.cs:28:17:28:23 | object creation of type A : A | ArrayFlow.cs:33:20:33:22 | access to local variable as : A[] | -| ArrayFlow.cs:32:18:32:20 | access to local variable as : A[] | ArrayFlow.cs:208:40:208:41 | ts : A[] | -| ArrayFlow.cs:33:20:33:22 | access to local variable as : A[] | ArrayFlow.cs:33:14:33:23 | call to method First | -| ArrayFlow.cs:48:17:48:23 | object creation of type A : A | ArrayFlow.cs:51:14:51:20 | access to indexer | -| ArrayFlow.cs:48:17:48:23 | object creation of type A : A | ArrayFlow.cs:52:22:52:25 | access to local variable list : List | -| ArrayFlow.cs:48:17:48:23 | object creation of type A : A | ArrayFlow.cs:53:24:53:27 | access to local variable list : List | -| ArrayFlow.cs:49:20:49:32 | object creation of type List : List | ArrayFlow.cs:51:14:51:20 | access to indexer | -| ArrayFlow.cs:49:20:49:32 | object creation of type List : List | ArrayFlow.cs:52:22:52:25 | access to local variable list : List | -| ArrayFlow.cs:49:20:49:32 | object creation of type List : List | ArrayFlow.cs:53:24:53:27 | access to local variable list : List | -| ArrayFlow.cs:52:22:52:25 | access to local variable list : List | ArrayFlow.cs:210:49:210:52 | list : List | -| ArrayFlow.cs:53:24:53:27 | access to local variable list : List | ArrayFlow.cs:53:14:53:28 | call to method ListFirst | -| ArrayFlow.cs:58:20:58:32 | object creation of type List : List | ArrayFlow.cs:60:14:60:20 | access to indexer | -| ArrayFlow.cs:58:20:58:32 | object creation of type List : List | ArrayFlow.cs:61:22:61:25 | access to local variable list : List | -| ArrayFlow.cs:58:20:58:32 | object creation of type List : List | ArrayFlow.cs:62:24:62:27 | access to local variable list : List | -| ArrayFlow.cs:61:22:61:25 | access to local variable list : List | ArrayFlow.cs:210:49:210:52 | list : List | -| ArrayFlow.cs:62:24:62:27 | access to local variable list : List | ArrayFlow.cs:62:14:62:28 | call to method ListFirst | -| ArrayFlow.cs:67:17:67:23 | object creation of type A : A | ArrayFlow.cs:69:14:69:20 | access to indexer | -| ArrayFlow.cs:67:17:67:23 | object creation of type A : A | ArrayFlow.cs:70:22:70:25 | access to local variable list : List | -| ArrayFlow.cs:67:17:67:23 | object creation of type A : A | ArrayFlow.cs:71:24:71:27 | access to local variable list : List | -| ArrayFlow.cs:68:20:68:38 | object creation of type List : List | ArrayFlow.cs:69:14:69:20 | access to indexer | -| ArrayFlow.cs:68:20:68:38 | object creation of type List : List | ArrayFlow.cs:70:22:70:25 | access to local variable list : List | -| ArrayFlow.cs:68:20:68:38 | object creation of type List : List | ArrayFlow.cs:71:24:71:27 | access to local variable list : List | -| ArrayFlow.cs:70:22:70:25 | access to local variable list : List | ArrayFlow.cs:210:49:210:52 | list : List | -| ArrayFlow.cs:71:24:71:27 | access to local variable list : List | ArrayFlow.cs:71:14:71:28 | call to method ListFirst | -| ArrayFlow.cs:76:20:76:42 | object creation of type List : List | ArrayFlow.cs:77:14:77:20 | access to indexer | -| ArrayFlow.cs:76:20:76:42 | object creation of type List : List | ArrayFlow.cs:78:22:78:25 | access to local variable list : List | -| ArrayFlow.cs:76:20:76:42 | object creation of type List : List | ArrayFlow.cs:79:24:79:27 | access to local variable list : List | -| ArrayFlow.cs:78:22:78:25 | access to local variable list : List | ArrayFlow.cs:210:49:210:52 | list : List | -| ArrayFlow.cs:79:24:79:27 | access to local variable list : List | ArrayFlow.cs:79:14:79:28 | call to method ListFirst | -| ArrayFlow.cs:84:17:84:23 | object creation of type A : A | ArrayFlow.cs:87:14:87:20 | access to indexer | -| ArrayFlow.cs:84:17:84:23 | object creation of type A : A | ArrayFlow.cs:88:22:88:25 | access to local variable list : List | -| ArrayFlow.cs:84:17:84:23 | object creation of type A : A | ArrayFlow.cs:89:24:89:27 | access to local variable list : List | -| ArrayFlow.cs:85:20:85:32 | object creation of type List : List | ArrayFlow.cs:87:14:87:20 | access to indexer | -| ArrayFlow.cs:85:20:85:32 | object creation of type List : List | ArrayFlow.cs:88:22:88:25 | access to local variable list : List | -| ArrayFlow.cs:85:20:85:32 | object creation of type List : List | ArrayFlow.cs:89:24:89:27 | access to local variable list : List | -| ArrayFlow.cs:88:22:88:25 | access to local variable list : List | ArrayFlow.cs:210:49:210:52 | list : List | -| ArrayFlow.cs:89:24:89:27 | access to local variable list : List | ArrayFlow.cs:89:14:89:28 | call to method ListFirst | -| ArrayFlow.cs:94:20:94:32 | object creation of type List : List | ArrayFlow.cs:96:14:96:20 | access to indexer | -| ArrayFlow.cs:94:20:94:32 | object creation of type List : List | ArrayFlow.cs:97:22:97:25 | access to local variable list : List | -| ArrayFlow.cs:94:20:94:32 | object creation of type List : List | ArrayFlow.cs:98:24:98:27 | access to local variable list : List | -| ArrayFlow.cs:97:22:97:25 | access to local variable list : List | ArrayFlow.cs:210:49:210:52 | list : List | -| ArrayFlow.cs:98:24:98:27 | access to local variable list : List | ArrayFlow.cs:98:14:98:28 | call to method ListFirst | -| ArrayFlow.cs:103:17:103:23 | object creation of type A : A | ArrayFlow.cs:106:14:106:20 | access to indexer | -| ArrayFlow.cs:103:17:103:23 | object creation of type A : A | ArrayFlow.cs:107:23:107:26 | access to local variable dict : Dictionary | -| ArrayFlow.cs:103:17:103:23 | object creation of type A : A | ArrayFlow.cs:108:30:108:33 | access to local variable dict : Dictionary | -| ArrayFlow.cs:103:17:103:23 | object creation of type A : A | ArrayFlow.cs:110:30:110:33 | access to local variable dict : Dictionary | -| ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:106:14:106:20 | access to indexer | -| ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:107:23:107:26 | access to local variable dict : Dictionary | -| ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:108:30:108:33 | access to local variable dict : Dictionary | -| ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:110:30:110:33 | access to local variable dict : Dictionary | -| ArrayFlow.cs:107:23:107:26 | access to local variable dict : Dictionary | ArrayFlow.cs:212:61:212:64 | dict : Dictionary | -| ArrayFlow.cs:108:30:108:33 | access to local variable dict : Dictionary | ArrayFlow.cs:108:14:108:34 | call to method DictFirstValueA | -| ArrayFlow.cs:110:30:110:33 | access to local variable dict : Dictionary | ArrayFlow.cs:110:14:110:34 | call to method DictFirstValueC | -| ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:117:14:117:20 | access to indexer | -| ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:118:23:118:26 | access to local variable dict : Dictionary | -| ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:119:30:119:33 | access to local variable dict : Dictionary | -| ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:121:30:121:33 | access to local variable dict : Dictionary | -| ArrayFlow.cs:118:23:118:26 | access to local variable dict : Dictionary | ArrayFlow.cs:212:61:212:64 | dict : Dictionary | -| ArrayFlow.cs:119:30:119:33 | access to local variable dict : Dictionary | ArrayFlow.cs:119:14:119:34 | call to method DictFirstValueA | -| ArrayFlow.cs:121:30:121:33 | access to local variable dict : Dictionary | ArrayFlow.cs:121:14:121:34 | call to method DictFirstValueC | -| ArrayFlow.cs:126:17:126:23 | object creation of type A : A | ArrayFlow.cs:128:14:128:20 | access to indexer | -| ArrayFlow.cs:126:17:126:23 | object creation of type A : A | ArrayFlow.cs:129:23:129:26 | access to local variable dict : Dictionary | -| ArrayFlow.cs:126:17:126:23 | object creation of type A : A | ArrayFlow.cs:130:30:130:33 | access to local variable dict : Dictionary | -| ArrayFlow.cs:126:17:126:23 | object creation of type A : A | ArrayFlow.cs:132:30:132:33 | access to local variable dict : Dictionary | -| ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:128:14:128:20 | access to indexer | -| ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:129:23:129:26 | access to local variable dict : Dictionary | -| ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:130:30:130:33 | access to local variable dict : Dictionary | -| ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:132:30:132:33 | access to local variable dict : Dictionary | -| ArrayFlow.cs:129:23:129:26 | access to local variable dict : Dictionary | ArrayFlow.cs:212:61:212:64 | dict : Dictionary | -| ArrayFlow.cs:130:30:130:33 | access to local variable dict : Dictionary | ArrayFlow.cs:130:14:130:34 | call to method DictFirstValueA | -| ArrayFlow.cs:132:30:132:33 | access to local variable dict : Dictionary | ArrayFlow.cs:132:14:132:34 | call to method DictFirstValueC | -| ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:138:14:138:20 | access to indexer | -| ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:139:23:139:26 | access to local variable dict : Dictionary | -| ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:140:30:140:33 | access to local variable dict : Dictionary | -| ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:142:30:142:33 | access to local variable dict : Dictionary | -| ArrayFlow.cs:139:23:139:26 | access to local variable dict : Dictionary | ArrayFlow.cs:212:61:212:64 | dict : Dictionary | -| ArrayFlow.cs:140:30:140:33 | access to local variable dict : Dictionary | ArrayFlow.cs:140:14:140:34 | call to method DictFirstValueA | -| ArrayFlow.cs:142:30:142:33 | access to local variable dict : Dictionary | ArrayFlow.cs:142:14:142:34 | call to method DictFirstValueC | -| ArrayFlow.cs:166:17:166:23 | object creation of type A : A | ArrayFlow.cs:169:18:169:18 | access to local variable x | -| ArrayFlow.cs:181:17:181:23 | object creation of type A : A | ArrayFlow.cs:185:18:185:35 | access to property Current | -| ArrayFlow.cs:208:40:208:41 | ts : A[] | ArrayFlow.cs:208:52:208:56 | access to array element | -| ArrayFlow.cs:210:49:210:52 | list : List | ArrayFlow.cs:210:63:210:69 | access to indexer | -| ArrayFlow.cs:212:61:212:64 | dict : Dictionary | ArrayFlow.cs:212:75:212:81 | access to indexer | -nodes -| ArrayFlow.cs:10:17:10:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| ArrayFlow.cs:12:14:12:19 | access to array element | semmle.label | access to array element | -| ArrayFlow.cs:13:18:13:20 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | -| ArrayFlow.cs:14:14:14:23 | call to method First | semmle.label | call to method First | -| ArrayFlow.cs:14:20:14:22 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | -| ArrayFlow.cs:28:17:28:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| ArrayFlow.cs:31:14:31:19 | access to array element | semmle.label | access to array element | -| ArrayFlow.cs:32:18:32:20 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | -| ArrayFlow.cs:33:14:33:23 | call to method First | semmle.label | call to method First | -| ArrayFlow.cs:33:20:33:22 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | -| ArrayFlow.cs:48:17:48:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| ArrayFlow.cs:49:20:49:32 | object creation of type List : List | semmle.label | object creation of type List : List | -| ArrayFlow.cs:51:14:51:20 | access to indexer | semmle.label | access to indexer | -| ArrayFlow.cs:52:22:52:25 | access to local variable list : List | semmle.label | access to local variable list : List | -| ArrayFlow.cs:53:14:53:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| ArrayFlow.cs:53:24:53:27 | access to local variable list : List | semmle.label | access to local variable list : List | -| ArrayFlow.cs:58:20:58:32 | object creation of type List : List | semmle.label | object creation of type List : List | -| ArrayFlow.cs:60:14:60:20 | access to indexer | semmle.label | access to indexer | -| ArrayFlow.cs:61:22:61:25 | access to local variable list : List | semmle.label | access to local variable list : List | -| ArrayFlow.cs:62:14:62:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| ArrayFlow.cs:62:24:62:27 | access to local variable list : List | semmle.label | access to local variable list : List | -| ArrayFlow.cs:67:17:67:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| ArrayFlow.cs:68:20:68:38 | object creation of type List : List | semmle.label | object creation of type List : List | -| ArrayFlow.cs:69:14:69:20 | access to indexer | semmle.label | access to indexer | -| ArrayFlow.cs:70:22:70:25 | access to local variable list : List | semmle.label | access to local variable list : List | -| ArrayFlow.cs:71:14:71:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| ArrayFlow.cs:71:24:71:27 | access to local variable list : List | semmle.label | access to local variable list : List | -| ArrayFlow.cs:76:20:76:42 | object creation of type List : List | semmle.label | object creation of type List : List | -| ArrayFlow.cs:77:14:77:20 | access to indexer | semmle.label | access to indexer | -| ArrayFlow.cs:78:22:78:25 | access to local variable list : List | semmle.label | access to local variable list : List | -| ArrayFlow.cs:79:14:79:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| ArrayFlow.cs:79:24:79:27 | access to local variable list : List | semmle.label | access to local variable list : List | -| ArrayFlow.cs:84:17:84:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| ArrayFlow.cs:85:20:85:32 | object creation of type List : List | semmle.label | object creation of type List : List | -| ArrayFlow.cs:87:14:87:20 | access to indexer | semmle.label | access to indexer | -| ArrayFlow.cs:88:22:88:25 | access to local variable list : List | semmle.label | access to local variable list : List | -| ArrayFlow.cs:89:14:89:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| ArrayFlow.cs:89:24:89:27 | access to local variable list : List | semmle.label | access to local variable list : List | -| ArrayFlow.cs:94:20:94:32 | object creation of type List : List | semmle.label | object creation of type List : List | -| ArrayFlow.cs:96:14:96:20 | access to indexer | semmle.label | access to indexer | -| ArrayFlow.cs:97:22:97:25 | access to local variable list : List | semmle.label | access to local variable list : List | -| ArrayFlow.cs:98:14:98:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| ArrayFlow.cs:98:24:98:27 | access to local variable list : List | semmle.label | access to local variable list : List | -| ArrayFlow.cs:103:17:103:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | -| ArrayFlow.cs:106:14:106:20 | access to indexer | semmle.label | access to indexer | -| ArrayFlow.cs:107:23:107:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| ArrayFlow.cs:108:14:108:34 | call to method DictFirstValueA | semmle.label | call to method DictFirstValueA | -| ArrayFlow.cs:108:30:108:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| ArrayFlow.cs:110:14:110:34 | call to method DictFirstValueC | semmle.label | call to method DictFirstValueC | -| ArrayFlow.cs:110:30:110:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | -| ArrayFlow.cs:117:14:117:20 | access to indexer | semmle.label | access to indexer | -| ArrayFlow.cs:118:23:118:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| ArrayFlow.cs:119:14:119:34 | call to method DictFirstValueA | semmle.label | call to method DictFirstValueA | -| ArrayFlow.cs:119:30:119:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| ArrayFlow.cs:121:14:121:34 | call to method DictFirstValueC | semmle.label | call to method DictFirstValueC | -| ArrayFlow.cs:121:30:121:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| ArrayFlow.cs:126:17:126:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | -| ArrayFlow.cs:128:14:128:20 | access to indexer | semmle.label | access to indexer | -| ArrayFlow.cs:129:23:129:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| ArrayFlow.cs:130:14:130:34 | call to method DictFirstValueA | semmle.label | call to method DictFirstValueA | -| ArrayFlow.cs:130:30:130:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| ArrayFlow.cs:132:14:132:34 | call to method DictFirstValueC | semmle.label | call to method DictFirstValueC | -| ArrayFlow.cs:132:30:132:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | -| ArrayFlow.cs:138:14:138:20 | access to indexer | semmle.label | access to indexer | -| ArrayFlow.cs:139:23:139:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| ArrayFlow.cs:140:14:140:34 | call to method DictFirstValueA | semmle.label | call to method DictFirstValueA | -| ArrayFlow.cs:140:30:140:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| ArrayFlow.cs:142:14:142:34 | call to method DictFirstValueC | semmle.label | call to method DictFirstValueC | -| ArrayFlow.cs:142:30:142:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| ArrayFlow.cs:166:17:166:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| ArrayFlow.cs:169:18:169:18 | access to local variable x | semmle.label | access to local variable x | -| ArrayFlow.cs:181:17:181:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| ArrayFlow.cs:185:18:185:35 | access to property Current | semmle.label | access to property Current | -| ArrayFlow.cs:208:40:208:41 | ts : A[] | semmle.label | ts : A[] | -| ArrayFlow.cs:208:52:208:56 | access to array element | semmle.label | access to array element | -| ArrayFlow.cs:210:49:210:52 | list : List | semmle.label | list : List | -| ArrayFlow.cs:210:63:210:69 | access to indexer | semmle.label | access to indexer | -| ArrayFlow.cs:212:61:212:64 | dict : Dictionary | semmle.label | dict : Dictionary | -| ArrayFlow.cs:212:75:212:81 | access to indexer | semmle.label | access to indexer | -#select -| ArrayFlow.cs:10:17:10:23 | object creation of type A : A | ArrayFlow.cs:10:17:10:23 | object creation of type A : A | ArrayFlow.cs:12:14:12:19 | access to array element | $@ | ArrayFlow.cs:12:14:12:19 | access to array element | access to array element | -| ArrayFlow.cs:10:17:10:23 | object creation of type A : A | ArrayFlow.cs:10:17:10:23 | object creation of type A : A | ArrayFlow.cs:14:14:14:23 | call to method First | $@ | ArrayFlow.cs:14:14:14:23 | call to method First | call to method First | -| ArrayFlow.cs:10:17:10:23 | object creation of type A : A | ArrayFlow.cs:10:17:10:23 | object creation of type A : A | ArrayFlow.cs:208:52:208:56 | access to array element | $@ | ArrayFlow.cs:208:52:208:56 | access to array element | access to array element | -| ArrayFlow.cs:28:17:28:23 | object creation of type A : A | ArrayFlow.cs:28:17:28:23 | object creation of type A : A | ArrayFlow.cs:31:14:31:19 | access to array element | $@ | ArrayFlow.cs:31:14:31:19 | access to array element | access to array element | -| ArrayFlow.cs:28:17:28:23 | object creation of type A : A | ArrayFlow.cs:28:17:28:23 | object creation of type A : A | ArrayFlow.cs:33:14:33:23 | call to method First | $@ | ArrayFlow.cs:33:14:33:23 | call to method First | call to method First | -| ArrayFlow.cs:28:17:28:23 | object creation of type A : A | ArrayFlow.cs:28:17:28:23 | object creation of type A : A | ArrayFlow.cs:208:52:208:56 | access to array element | $@ | ArrayFlow.cs:208:52:208:56 | access to array element | access to array element | -| ArrayFlow.cs:48:17:48:23 | object creation of type A : A | ArrayFlow.cs:48:17:48:23 | object creation of type A : A | ArrayFlow.cs:51:14:51:20 | access to indexer | $@ | ArrayFlow.cs:51:14:51:20 | access to indexer | access to indexer | -| ArrayFlow.cs:48:17:48:23 | object creation of type A : A | ArrayFlow.cs:48:17:48:23 | object creation of type A : A | ArrayFlow.cs:53:14:53:28 | call to method ListFirst | $@ | ArrayFlow.cs:53:14:53:28 | call to method ListFirst | call to method ListFirst | -| ArrayFlow.cs:48:17:48:23 | object creation of type A : A | ArrayFlow.cs:48:17:48:23 | object creation of type A : A | ArrayFlow.cs:210:63:210:69 | access to indexer | $@ | ArrayFlow.cs:210:63:210:69 | access to indexer | access to indexer | -| ArrayFlow.cs:49:20:49:32 | object creation of type List : List | ArrayFlow.cs:49:20:49:32 | object creation of type List : List | ArrayFlow.cs:51:14:51:20 | access to indexer | $@ | ArrayFlow.cs:51:14:51:20 | access to indexer | access to indexer | -| ArrayFlow.cs:49:20:49:32 | object creation of type List : List | ArrayFlow.cs:49:20:49:32 | object creation of type List : List | ArrayFlow.cs:53:14:53:28 | call to method ListFirst | $@ | ArrayFlow.cs:53:14:53:28 | call to method ListFirst | call to method ListFirst | -| ArrayFlow.cs:49:20:49:32 | object creation of type List : List | ArrayFlow.cs:49:20:49:32 | object creation of type List : List | ArrayFlow.cs:210:63:210:69 | access to indexer | $@ | ArrayFlow.cs:210:63:210:69 | access to indexer | access to indexer | -| ArrayFlow.cs:58:20:58:32 | object creation of type List : List | ArrayFlow.cs:58:20:58:32 | object creation of type List : List | ArrayFlow.cs:60:14:60:20 | access to indexer | $@ | ArrayFlow.cs:60:14:60:20 | access to indexer | access to indexer | -| ArrayFlow.cs:58:20:58:32 | object creation of type List : List | ArrayFlow.cs:58:20:58:32 | object creation of type List : List | ArrayFlow.cs:62:14:62:28 | call to method ListFirst | $@ | ArrayFlow.cs:62:14:62:28 | call to method ListFirst | call to method ListFirst | -| ArrayFlow.cs:58:20:58:32 | object creation of type List : List | ArrayFlow.cs:58:20:58:32 | object creation of type List : List | ArrayFlow.cs:210:63:210:69 | access to indexer | $@ | ArrayFlow.cs:210:63:210:69 | access to indexer | access to indexer | -| ArrayFlow.cs:67:17:67:23 | object creation of type A : A | ArrayFlow.cs:67:17:67:23 | object creation of type A : A | ArrayFlow.cs:69:14:69:20 | access to indexer | $@ | ArrayFlow.cs:69:14:69:20 | access to indexer | access to indexer | -| ArrayFlow.cs:67:17:67:23 | object creation of type A : A | ArrayFlow.cs:67:17:67:23 | object creation of type A : A | ArrayFlow.cs:71:14:71:28 | call to method ListFirst | $@ | ArrayFlow.cs:71:14:71:28 | call to method ListFirst | call to method ListFirst | -| ArrayFlow.cs:67:17:67:23 | object creation of type A : A | ArrayFlow.cs:67:17:67:23 | object creation of type A : A | ArrayFlow.cs:210:63:210:69 | access to indexer | $@ | ArrayFlow.cs:210:63:210:69 | access to indexer | access to indexer | -| ArrayFlow.cs:68:20:68:38 | object creation of type List : List | ArrayFlow.cs:68:20:68:38 | object creation of type List : List | ArrayFlow.cs:69:14:69:20 | access to indexer | $@ | ArrayFlow.cs:69:14:69:20 | access to indexer | access to indexer | -| ArrayFlow.cs:68:20:68:38 | object creation of type List : List | ArrayFlow.cs:68:20:68:38 | object creation of type List : List | ArrayFlow.cs:71:14:71:28 | call to method ListFirst | $@ | ArrayFlow.cs:71:14:71:28 | call to method ListFirst | call to method ListFirst | -| ArrayFlow.cs:68:20:68:38 | object creation of type List : List | ArrayFlow.cs:68:20:68:38 | object creation of type List : List | ArrayFlow.cs:210:63:210:69 | access to indexer | $@ | ArrayFlow.cs:210:63:210:69 | access to indexer | access to indexer | -| ArrayFlow.cs:76:20:76:42 | object creation of type List : List | ArrayFlow.cs:76:20:76:42 | object creation of type List : List | ArrayFlow.cs:77:14:77:20 | access to indexer | $@ | ArrayFlow.cs:77:14:77:20 | access to indexer | access to indexer | -| ArrayFlow.cs:76:20:76:42 | object creation of type List : List | ArrayFlow.cs:76:20:76:42 | object creation of type List : List | ArrayFlow.cs:79:14:79:28 | call to method ListFirst | $@ | ArrayFlow.cs:79:14:79:28 | call to method ListFirst | call to method ListFirst | -| ArrayFlow.cs:76:20:76:42 | object creation of type List : List | ArrayFlow.cs:76:20:76:42 | object creation of type List : List | ArrayFlow.cs:210:63:210:69 | access to indexer | $@ | ArrayFlow.cs:210:63:210:69 | access to indexer | access to indexer | -| ArrayFlow.cs:84:17:84:23 | object creation of type A : A | ArrayFlow.cs:84:17:84:23 | object creation of type A : A | ArrayFlow.cs:87:14:87:20 | access to indexer | $@ | ArrayFlow.cs:87:14:87:20 | access to indexer | access to indexer | -| ArrayFlow.cs:84:17:84:23 | object creation of type A : A | ArrayFlow.cs:84:17:84:23 | object creation of type A : A | ArrayFlow.cs:89:14:89:28 | call to method ListFirst | $@ | ArrayFlow.cs:89:14:89:28 | call to method ListFirst | call to method ListFirst | -| ArrayFlow.cs:84:17:84:23 | object creation of type A : A | ArrayFlow.cs:84:17:84:23 | object creation of type A : A | ArrayFlow.cs:210:63:210:69 | access to indexer | $@ | ArrayFlow.cs:210:63:210:69 | access to indexer | access to indexer | -| ArrayFlow.cs:85:20:85:32 | object creation of type List : List | ArrayFlow.cs:85:20:85:32 | object creation of type List : List | ArrayFlow.cs:87:14:87:20 | access to indexer | $@ | ArrayFlow.cs:87:14:87:20 | access to indexer | access to indexer | -| ArrayFlow.cs:85:20:85:32 | object creation of type List : List | ArrayFlow.cs:85:20:85:32 | object creation of type List : List | ArrayFlow.cs:89:14:89:28 | call to method ListFirst | $@ | ArrayFlow.cs:89:14:89:28 | call to method ListFirst | call to method ListFirst | -| ArrayFlow.cs:85:20:85:32 | object creation of type List : List | ArrayFlow.cs:85:20:85:32 | object creation of type List : List | ArrayFlow.cs:210:63:210:69 | access to indexer | $@ | ArrayFlow.cs:210:63:210:69 | access to indexer | access to indexer | -| ArrayFlow.cs:94:20:94:32 | object creation of type List : List | ArrayFlow.cs:94:20:94:32 | object creation of type List : List | ArrayFlow.cs:96:14:96:20 | access to indexer | $@ | ArrayFlow.cs:96:14:96:20 | access to indexer | access to indexer | -| ArrayFlow.cs:94:20:94:32 | object creation of type List : List | ArrayFlow.cs:94:20:94:32 | object creation of type List : List | ArrayFlow.cs:98:14:98:28 | call to method ListFirst | $@ | ArrayFlow.cs:98:14:98:28 | call to method ListFirst | call to method ListFirst | -| ArrayFlow.cs:94:20:94:32 | object creation of type List : List | ArrayFlow.cs:94:20:94:32 | object creation of type List : List | ArrayFlow.cs:210:63:210:69 | access to indexer | $@ | ArrayFlow.cs:210:63:210:69 | access to indexer | access to indexer | -| ArrayFlow.cs:103:17:103:23 | object creation of type A : A | ArrayFlow.cs:103:17:103:23 | object creation of type A : A | ArrayFlow.cs:106:14:106:20 | access to indexer | $@ | ArrayFlow.cs:106:14:106:20 | access to indexer | access to indexer | -| ArrayFlow.cs:103:17:103:23 | object creation of type A : A | ArrayFlow.cs:103:17:103:23 | object creation of type A : A | ArrayFlow.cs:108:14:108:34 | call to method DictFirstValueA | $@ | ArrayFlow.cs:108:14:108:34 | call to method DictFirstValueA | call to method DictFirstValueA | -| ArrayFlow.cs:103:17:103:23 | object creation of type A : A | ArrayFlow.cs:103:17:103:23 | object creation of type A : A | ArrayFlow.cs:110:14:110:34 | call to method DictFirstValueC | $@ | ArrayFlow.cs:110:14:110:34 | call to method DictFirstValueC | call to method DictFirstValueC | -| ArrayFlow.cs:103:17:103:23 | object creation of type A : A | ArrayFlow.cs:103:17:103:23 | object creation of type A : A | ArrayFlow.cs:212:75:212:81 | access to indexer | $@ | ArrayFlow.cs:212:75:212:81 | access to indexer | access to indexer | -| ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:106:14:106:20 | access to indexer | $@ | ArrayFlow.cs:106:14:106:20 | access to indexer | access to indexer | -| ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:108:14:108:34 | call to method DictFirstValueA | $@ | ArrayFlow.cs:108:14:108:34 | call to method DictFirstValueA | call to method DictFirstValueA | -| ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:110:14:110:34 | call to method DictFirstValueC | $@ | ArrayFlow.cs:110:14:110:34 | call to method DictFirstValueC | call to method DictFirstValueC | -| ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:212:75:212:81 | access to indexer | $@ | ArrayFlow.cs:212:75:212:81 | access to indexer | access to indexer | -| ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:117:14:117:20 | access to indexer | $@ | ArrayFlow.cs:117:14:117:20 | access to indexer | access to indexer | -| ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:119:14:119:34 | call to method DictFirstValueA | $@ | ArrayFlow.cs:119:14:119:34 | call to method DictFirstValueA | call to method DictFirstValueA | -| ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:121:14:121:34 | call to method DictFirstValueC | $@ | ArrayFlow.cs:121:14:121:34 | call to method DictFirstValueC | call to method DictFirstValueC | -| ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:212:75:212:81 | access to indexer | $@ | ArrayFlow.cs:212:75:212:81 | access to indexer | access to indexer | -| ArrayFlow.cs:126:17:126:23 | object creation of type A : A | ArrayFlow.cs:126:17:126:23 | object creation of type A : A | ArrayFlow.cs:128:14:128:20 | access to indexer | $@ | ArrayFlow.cs:128:14:128:20 | access to indexer | access to indexer | -| ArrayFlow.cs:126:17:126:23 | object creation of type A : A | ArrayFlow.cs:126:17:126:23 | object creation of type A : A | ArrayFlow.cs:130:14:130:34 | call to method DictFirstValueA | $@ | ArrayFlow.cs:130:14:130:34 | call to method DictFirstValueA | call to method DictFirstValueA | -| ArrayFlow.cs:126:17:126:23 | object creation of type A : A | ArrayFlow.cs:126:17:126:23 | object creation of type A : A | ArrayFlow.cs:132:14:132:34 | call to method DictFirstValueC | $@ | ArrayFlow.cs:132:14:132:34 | call to method DictFirstValueC | call to method DictFirstValueC | -| ArrayFlow.cs:126:17:126:23 | object creation of type A : A | ArrayFlow.cs:126:17:126:23 | object creation of type A : A | ArrayFlow.cs:212:75:212:81 | access to indexer | $@ | ArrayFlow.cs:212:75:212:81 | access to indexer | access to indexer | -| ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:128:14:128:20 | access to indexer | $@ | ArrayFlow.cs:128:14:128:20 | access to indexer | access to indexer | -| ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:130:14:130:34 | call to method DictFirstValueA | $@ | ArrayFlow.cs:130:14:130:34 | call to method DictFirstValueA | call to method DictFirstValueA | -| ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:132:14:132:34 | call to method DictFirstValueC | $@ | ArrayFlow.cs:132:14:132:34 | call to method DictFirstValueC | call to method DictFirstValueC | -| ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:212:75:212:81 | access to indexer | $@ | ArrayFlow.cs:212:75:212:81 | access to indexer | access to indexer | -| ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:138:14:138:20 | access to indexer | $@ | ArrayFlow.cs:138:14:138:20 | access to indexer | access to indexer | -| ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:140:14:140:34 | call to method DictFirstValueA | $@ | ArrayFlow.cs:140:14:140:34 | call to method DictFirstValueA | call to method DictFirstValueA | -| ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:142:14:142:34 | call to method DictFirstValueC | $@ | ArrayFlow.cs:142:14:142:34 | call to method DictFirstValueC | call to method DictFirstValueC | -| ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | ArrayFlow.cs:212:75:212:81 | access to indexer | $@ | ArrayFlow.cs:212:75:212:81 | access to indexer | access to indexer | -| ArrayFlow.cs:166:17:166:23 | object creation of type A : A | ArrayFlow.cs:166:17:166:23 | object creation of type A : A | ArrayFlow.cs:169:18:169:18 | access to local variable x | $@ | ArrayFlow.cs:169:18:169:18 | access to local variable x | access to local variable x | -| ArrayFlow.cs:181:17:181:23 | object creation of type A : A | ArrayFlow.cs:181:17:181:23 | object creation of type A : A | ArrayFlow.cs:185:18:185:35 | access to property Current | $@ | ArrayFlow.cs:185:18:185:35 | access to property Current | access to property Current | diff --git a/csharp/ql/test/library-tests/dataflow/arrays/ArrayFlow.cs b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs similarity index 100% rename from csharp/ql/test/library-tests/dataflow/arrays/ArrayFlow.cs rename to csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected new file mode 100644 index 00000000000..d0019ee529e --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected @@ -0,0 +1,235 @@ +edges +| CollectionFlow.cs:10:17:10:23 | object creation of type A : A | CollectionFlow.cs:12:14:12:19 | access to array element | +| CollectionFlow.cs:10:17:10:23 | object creation of type A : A | CollectionFlow.cs:13:18:13:20 | access to local variable as : A[] | +| CollectionFlow.cs:10:17:10:23 | object creation of type A : A | CollectionFlow.cs:14:20:14:22 | access to local variable as : A[] | +| CollectionFlow.cs:13:18:13:20 | access to local variable as : A[] | CollectionFlow.cs:208:40:208:41 | ts : A[] | +| CollectionFlow.cs:14:20:14:22 | access to local variable as : A[] | CollectionFlow.cs:14:14:14:23 | call to method First | +| CollectionFlow.cs:28:17:28:23 | object creation of type A : A | CollectionFlow.cs:31:14:31:19 | access to array element | +| CollectionFlow.cs:28:17:28:23 | object creation of type A : A | CollectionFlow.cs:32:18:32:20 | access to local variable as : A[] | +| CollectionFlow.cs:28:17:28:23 | object creation of type A : A | CollectionFlow.cs:33:20:33:22 | access to local variable as : A[] | +| CollectionFlow.cs:32:18:32:20 | access to local variable as : A[] | CollectionFlow.cs:208:40:208:41 | ts : A[] | +| CollectionFlow.cs:33:20:33:22 | access to local variable as : A[] | CollectionFlow.cs:33:14:33:23 | call to method First | +| CollectionFlow.cs:48:17:48:23 | object creation of type A : A | CollectionFlow.cs:51:14:51:20 | access to indexer | +| CollectionFlow.cs:48:17:48:23 | object creation of type A : A | CollectionFlow.cs:52:22:52:25 | access to local variable list : List | +| CollectionFlow.cs:48:17:48:23 | object creation of type A : A | CollectionFlow.cs:53:24:53:27 | access to local variable list : List | +| CollectionFlow.cs:49:20:49:32 | object creation of type List : List | CollectionFlow.cs:51:14:51:20 | access to indexer | +| CollectionFlow.cs:49:20:49:32 | object creation of type List : List | CollectionFlow.cs:52:22:52:25 | access to local variable list : List | +| CollectionFlow.cs:49:20:49:32 | object creation of type List : List | CollectionFlow.cs:53:24:53:27 | access to local variable list : List | +| CollectionFlow.cs:52:22:52:25 | access to local variable list : List | CollectionFlow.cs:210:49:210:52 | list : List | +| CollectionFlow.cs:53:24:53:27 | access to local variable list : List | CollectionFlow.cs:53:14:53:28 | call to method ListFirst | +| CollectionFlow.cs:58:20:58:32 | object creation of type List : List | CollectionFlow.cs:60:14:60:20 | access to indexer | +| CollectionFlow.cs:58:20:58:32 | object creation of type List : List | CollectionFlow.cs:61:22:61:25 | access to local variable list : List | +| CollectionFlow.cs:58:20:58:32 | object creation of type List : List | CollectionFlow.cs:62:24:62:27 | access to local variable list : List | +| CollectionFlow.cs:61:22:61:25 | access to local variable list : List | CollectionFlow.cs:210:49:210:52 | list : List | +| CollectionFlow.cs:62:24:62:27 | access to local variable list : List | CollectionFlow.cs:62:14:62:28 | call to method ListFirst | +| CollectionFlow.cs:67:17:67:23 | object creation of type A : A | CollectionFlow.cs:69:14:69:20 | access to indexer | +| CollectionFlow.cs:67:17:67:23 | object creation of type A : A | CollectionFlow.cs:70:22:70:25 | access to local variable list : List | +| CollectionFlow.cs:67:17:67:23 | object creation of type A : A | CollectionFlow.cs:71:24:71:27 | access to local variable list : List | +| CollectionFlow.cs:68:20:68:38 | object creation of type List : List | CollectionFlow.cs:69:14:69:20 | access to indexer | +| CollectionFlow.cs:68:20:68:38 | object creation of type List : List | CollectionFlow.cs:70:22:70:25 | access to local variable list : List | +| CollectionFlow.cs:68:20:68:38 | object creation of type List : List | CollectionFlow.cs:71:24:71:27 | access to local variable list : List | +| CollectionFlow.cs:70:22:70:25 | access to local variable list : List | CollectionFlow.cs:210:49:210:52 | list : List | +| CollectionFlow.cs:71:24:71:27 | access to local variable list : List | CollectionFlow.cs:71:14:71:28 | call to method ListFirst | +| CollectionFlow.cs:76:20:76:42 | object creation of type List : List | CollectionFlow.cs:77:14:77:20 | access to indexer | +| CollectionFlow.cs:76:20:76:42 | object creation of type List : List | CollectionFlow.cs:78:22:78:25 | access to local variable list : List | +| CollectionFlow.cs:76:20:76:42 | object creation of type List : List | CollectionFlow.cs:79:24:79:27 | access to local variable list : List | +| CollectionFlow.cs:78:22:78:25 | access to local variable list : List | CollectionFlow.cs:210:49:210:52 | list : List | +| CollectionFlow.cs:79:24:79:27 | access to local variable list : List | CollectionFlow.cs:79:14:79:28 | call to method ListFirst | +| CollectionFlow.cs:84:17:84:23 | object creation of type A : A | CollectionFlow.cs:87:14:87:20 | access to indexer | +| CollectionFlow.cs:84:17:84:23 | object creation of type A : A | CollectionFlow.cs:88:22:88:25 | access to local variable list : List | +| CollectionFlow.cs:84:17:84:23 | object creation of type A : A | CollectionFlow.cs:89:24:89:27 | access to local variable list : List | +| CollectionFlow.cs:85:20:85:32 | object creation of type List : List | CollectionFlow.cs:87:14:87:20 | access to indexer | +| CollectionFlow.cs:85:20:85:32 | object creation of type List : List | CollectionFlow.cs:88:22:88:25 | access to local variable list : List | +| CollectionFlow.cs:85:20:85:32 | object creation of type List : List | CollectionFlow.cs:89:24:89:27 | access to local variable list : List | +| CollectionFlow.cs:88:22:88:25 | access to local variable list : List | CollectionFlow.cs:210:49:210:52 | list : List | +| CollectionFlow.cs:89:24:89:27 | access to local variable list : List | CollectionFlow.cs:89:14:89:28 | call to method ListFirst | +| CollectionFlow.cs:94:20:94:32 | object creation of type List : List | CollectionFlow.cs:96:14:96:20 | access to indexer | +| CollectionFlow.cs:94:20:94:32 | object creation of type List : List | CollectionFlow.cs:97:22:97:25 | access to local variable list : List | +| CollectionFlow.cs:94:20:94:32 | object creation of type List : List | CollectionFlow.cs:98:24:98:27 | access to local variable list : List | +| CollectionFlow.cs:97:22:97:25 | access to local variable list : List | CollectionFlow.cs:210:49:210:52 | list : List | +| CollectionFlow.cs:98:24:98:27 | access to local variable list : List | CollectionFlow.cs:98:14:98:28 | call to method ListFirst | +| CollectionFlow.cs:103:17:103:23 | object creation of type A : A | CollectionFlow.cs:106:14:106:20 | access to indexer | +| CollectionFlow.cs:103:17:103:23 | object creation of type A : A | CollectionFlow.cs:107:23:107:26 | access to local variable dict : Dictionary | +| CollectionFlow.cs:103:17:103:23 | object creation of type A : A | CollectionFlow.cs:108:30:108:33 | access to local variable dict : Dictionary | +| CollectionFlow.cs:103:17:103:23 | object creation of type A : A | CollectionFlow.cs:110:30:110:33 | access to local variable dict : Dictionary | +| CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:106:14:106:20 | access to indexer | +| CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:107:23:107:26 | access to local variable dict : Dictionary | +| CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:108:30:108:33 | access to local variable dict : Dictionary | +| CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:110:30:110:33 | access to local variable dict : Dictionary | +| CollectionFlow.cs:107:23:107:26 | access to local variable dict : Dictionary | CollectionFlow.cs:212:61:212:64 | dict : Dictionary | +| CollectionFlow.cs:108:30:108:33 | access to local variable dict : Dictionary | CollectionFlow.cs:108:14:108:34 | call to method DictFirstValueA | +| CollectionFlow.cs:110:30:110:33 | access to local variable dict : Dictionary | CollectionFlow.cs:110:14:110:34 | call to method DictFirstValueC | +| CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:117:14:117:20 | access to indexer | +| CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:118:23:118:26 | access to local variable dict : Dictionary | +| CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:119:30:119:33 | access to local variable dict : Dictionary | +| CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:121:30:121:33 | access to local variable dict : Dictionary | +| CollectionFlow.cs:118:23:118:26 | access to local variable dict : Dictionary | CollectionFlow.cs:212:61:212:64 | dict : Dictionary | +| CollectionFlow.cs:119:30:119:33 | access to local variable dict : Dictionary | CollectionFlow.cs:119:14:119:34 | call to method DictFirstValueA | +| CollectionFlow.cs:121:30:121:33 | access to local variable dict : Dictionary | CollectionFlow.cs:121:14:121:34 | call to method DictFirstValueC | +| CollectionFlow.cs:126:17:126:23 | object creation of type A : A | CollectionFlow.cs:128:14:128:20 | access to indexer | +| CollectionFlow.cs:126:17:126:23 | object creation of type A : A | CollectionFlow.cs:129:23:129:26 | access to local variable dict : Dictionary | +| CollectionFlow.cs:126:17:126:23 | object creation of type A : A | CollectionFlow.cs:130:30:130:33 | access to local variable dict : Dictionary | +| CollectionFlow.cs:126:17:126:23 | object creation of type A : A | CollectionFlow.cs:132:30:132:33 | access to local variable dict : Dictionary | +| CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:128:14:128:20 | access to indexer | +| CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:129:23:129:26 | access to local variable dict : Dictionary | +| CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:130:30:130:33 | access to local variable dict : Dictionary | +| CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:132:30:132:33 | access to local variable dict : Dictionary | +| CollectionFlow.cs:129:23:129:26 | access to local variable dict : Dictionary | CollectionFlow.cs:212:61:212:64 | dict : Dictionary | +| CollectionFlow.cs:130:30:130:33 | access to local variable dict : Dictionary | CollectionFlow.cs:130:14:130:34 | call to method DictFirstValueA | +| CollectionFlow.cs:132:30:132:33 | access to local variable dict : Dictionary | CollectionFlow.cs:132:14:132:34 | call to method DictFirstValueC | +| CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:138:14:138:20 | access to indexer | +| CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:139:23:139:26 | access to local variable dict : Dictionary | +| CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:140:30:140:33 | access to local variable dict : Dictionary | +| CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:142:30:142:33 | access to local variable dict : Dictionary | +| CollectionFlow.cs:139:23:139:26 | access to local variable dict : Dictionary | CollectionFlow.cs:212:61:212:64 | dict : Dictionary | +| CollectionFlow.cs:140:30:140:33 | access to local variable dict : Dictionary | CollectionFlow.cs:140:14:140:34 | call to method DictFirstValueA | +| CollectionFlow.cs:142:30:142:33 | access to local variable dict : Dictionary | CollectionFlow.cs:142:14:142:34 | call to method DictFirstValueC | +| CollectionFlow.cs:166:17:166:23 | object creation of type A : A | CollectionFlow.cs:169:18:169:18 | access to local variable x | +| CollectionFlow.cs:181:17:181:23 | object creation of type A : A | CollectionFlow.cs:185:18:185:35 | access to property Current | +| CollectionFlow.cs:208:40:208:41 | ts : A[] | CollectionFlow.cs:208:52:208:56 | access to array element | +| CollectionFlow.cs:210:49:210:52 | list : List | CollectionFlow.cs:210:63:210:69 | access to indexer | +| CollectionFlow.cs:212:61:212:64 | dict : Dictionary | CollectionFlow.cs:212:75:212:81 | access to indexer | +nodes +| CollectionFlow.cs:10:17:10:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:12:14:12:19 | access to array element | semmle.label | access to array element | +| CollectionFlow.cs:13:18:13:20 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | +| CollectionFlow.cs:14:14:14:23 | call to method First | semmle.label | call to method First | +| CollectionFlow.cs:14:20:14:22 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | +| CollectionFlow.cs:28:17:28:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:31:14:31:19 | access to array element | semmle.label | access to array element | +| CollectionFlow.cs:32:18:32:20 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | +| CollectionFlow.cs:33:14:33:23 | call to method First | semmle.label | call to method First | +| CollectionFlow.cs:33:20:33:22 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | +| CollectionFlow.cs:48:17:48:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:49:20:49:32 | object creation of type List : List | semmle.label | object creation of type List : List | +| CollectionFlow.cs:51:14:51:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:52:22:52:25 | access to local variable list : List | semmle.label | access to local variable list : List | +| CollectionFlow.cs:53:14:53:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| CollectionFlow.cs:53:24:53:27 | access to local variable list : List | semmle.label | access to local variable list : List | +| CollectionFlow.cs:58:20:58:32 | object creation of type List : List | semmle.label | object creation of type List : List | +| CollectionFlow.cs:60:14:60:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:61:22:61:25 | access to local variable list : List | semmle.label | access to local variable list : List | +| CollectionFlow.cs:62:14:62:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| CollectionFlow.cs:62:24:62:27 | access to local variable list : List | semmle.label | access to local variable list : List | +| CollectionFlow.cs:67:17:67:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:68:20:68:38 | object creation of type List : List | semmle.label | object creation of type List : List | +| CollectionFlow.cs:69:14:69:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:70:22:70:25 | access to local variable list : List | semmle.label | access to local variable list : List | +| CollectionFlow.cs:71:14:71:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| CollectionFlow.cs:71:24:71:27 | access to local variable list : List | semmle.label | access to local variable list : List | +| CollectionFlow.cs:76:20:76:42 | object creation of type List : List | semmle.label | object creation of type List : List | +| CollectionFlow.cs:77:14:77:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:78:22:78:25 | access to local variable list : List | semmle.label | access to local variable list : List | +| CollectionFlow.cs:79:14:79:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| CollectionFlow.cs:79:24:79:27 | access to local variable list : List | semmle.label | access to local variable list : List | +| CollectionFlow.cs:84:17:84:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:85:20:85:32 | object creation of type List : List | semmle.label | object creation of type List : List | +| CollectionFlow.cs:87:14:87:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:88:22:88:25 | access to local variable list : List | semmle.label | access to local variable list : List | +| CollectionFlow.cs:89:14:89:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| CollectionFlow.cs:89:24:89:27 | access to local variable list : List | semmle.label | access to local variable list : List | +| CollectionFlow.cs:94:20:94:32 | object creation of type List : List | semmle.label | object creation of type List : List | +| CollectionFlow.cs:96:14:96:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:97:22:97:25 | access to local variable list : List | semmle.label | access to local variable list : List | +| CollectionFlow.cs:98:14:98:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| CollectionFlow.cs:98:24:98:27 | access to local variable list : List | semmle.label | access to local variable list : List | +| CollectionFlow.cs:103:17:103:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | +| CollectionFlow.cs:106:14:106:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:107:23:107:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| CollectionFlow.cs:108:14:108:34 | call to method DictFirstValueA | semmle.label | call to method DictFirstValueA | +| CollectionFlow.cs:108:30:108:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| CollectionFlow.cs:110:14:110:34 | call to method DictFirstValueC | semmle.label | call to method DictFirstValueC | +| CollectionFlow.cs:110:30:110:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | +| CollectionFlow.cs:117:14:117:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:118:23:118:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| CollectionFlow.cs:119:14:119:34 | call to method DictFirstValueA | semmle.label | call to method DictFirstValueA | +| CollectionFlow.cs:119:30:119:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| CollectionFlow.cs:121:14:121:34 | call to method DictFirstValueC | semmle.label | call to method DictFirstValueC | +| CollectionFlow.cs:121:30:121:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| CollectionFlow.cs:126:17:126:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | +| CollectionFlow.cs:128:14:128:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:129:23:129:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| CollectionFlow.cs:130:14:130:34 | call to method DictFirstValueA | semmle.label | call to method DictFirstValueA | +| CollectionFlow.cs:130:30:130:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| CollectionFlow.cs:132:14:132:34 | call to method DictFirstValueC | semmle.label | call to method DictFirstValueC | +| CollectionFlow.cs:132:30:132:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | +| CollectionFlow.cs:138:14:138:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:139:23:139:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| CollectionFlow.cs:140:14:140:34 | call to method DictFirstValueA | semmle.label | call to method DictFirstValueA | +| CollectionFlow.cs:140:30:140:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| CollectionFlow.cs:142:14:142:34 | call to method DictFirstValueC | semmle.label | call to method DictFirstValueC | +| CollectionFlow.cs:142:30:142:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| CollectionFlow.cs:166:17:166:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:169:18:169:18 | access to local variable x | semmle.label | access to local variable x | +| CollectionFlow.cs:181:17:181:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:185:18:185:35 | access to property Current | semmle.label | access to property Current | +| CollectionFlow.cs:208:40:208:41 | ts : A[] | semmle.label | ts : A[] | +| CollectionFlow.cs:208:52:208:56 | access to array element | semmle.label | access to array element | +| CollectionFlow.cs:210:49:210:52 | list : List | semmle.label | list : List | +| CollectionFlow.cs:210:63:210:69 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:212:61:212:64 | dict : Dictionary | semmle.label | dict : Dictionary | +| CollectionFlow.cs:212:75:212:81 | access to indexer | semmle.label | access to indexer | +#select +| CollectionFlow.cs:10:17:10:23 | object creation of type A : A | CollectionFlow.cs:10:17:10:23 | object creation of type A : A | CollectionFlow.cs:12:14:12:19 | access to array element | $@ | CollectionFlow.cs:12:14:12:19 | access to array element | access to array element | +| CollectionFlow.cs:10:17:10:23 | object creation of type A : A | CollectionFlow.cs:10:17:10:23 | object creation of type A : A | CollectionFlow.cs:14:14:14:23 | call to method First | $@ | CollectionFlow.cs:14:14:14:23 | call to method First | call to method First | +| CollectionFlow.cs:10:17:10:23 | object creation of type A : A | CollectionFlow.cs:10:17:10:23 | object creation of type A : A | CollectionFlow.cs:208:52:208:56 | access to array element | $@ | CollectionFlow.cs:208:52:208:56 | access to array element | access to array element | +| CollectionFlow.cs:28:17:28:23 | object creation of type A : A | CollectionFlow.cs:28:17:28:23 | object creation of type A : A | CollectionFlow.cs:31:14:31:19 | access to array element | $@ | CollectionFlow.cs:31:14:31:19 | access to array element | access to array element | +| CollectionFlow.cs:28:17:28:23 | object creation of type A : A | CollectionFlow.cs:28:17:28:23 | object creation of type A : A | CollectionFlow.cs:33:14:33:23 | call to method First | $@ | CollectionFlow.cs:33:14:33:23 | call to method First | call to method First | +| CollectionFlow.cs:28:17:28:23 | object creation of type A : A | CollectionFlow.cs:28:17:28:23 | object creation of type A : A | CollectionFlow.cs:208:52:208:56 | access to array element | $@ | CollectionFlow.cs:208:52:208:56 | access to array element | access to array element | +| CollectionFlow.cs:48:17:48:23 | object creation of type A : A | CollectionFlow.cs:48:17:48:23 | object creation of type A : A | CollectionFlow.cs:51:14:51:20 | access to indexer | $@ | CollectionFlow.cs:51:14:51:20 | access to indexer | access to indexer | +| CollectionFlow.cs:48:17:48:23 | object creation of type A : A | CollectionFlow.cs:48:17:48:23 | object creation of type A : A | CollectionFlow.cs:53:14:53:28 | call to method ListFirst | $@ | CollectionFlow.cs:53:14:53:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:48:17:48:23 | object creation of type A : A | CollectionFlow.cs:48:17:48:23 | object creation of type A : A | CollectionFlow.cs:210:63:210:69 | access to indexer | $@ | CollectionFlow.cs:210:63:210:69 | access to indexer | access to indexer | +| CollectionFlow.cs:49:20:49:32 | object creation of type List : List | CollectionFlow.cs:49:20:49:32 | object creation of type List : List | CollectionFlow.cs:51:14:51:20 | access to indexer | $@ | CollectionFlow.cs:51:14:51:20 | access to indexer | access to indexer | +| CollectionFlow.cs:49:20:49:32 | object creation of type List : List | CollectionFlow.cs:49:20:49:32 | object creation of type List : List | CollectionFlow.cs:53:14:53:28 | call to method ListFirst | $@ | CollectionFlow.cs:53:14:53:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:49:20:49:32 | object creation of type List : List | CollectionFlow.cs:49:20:49:32 | object creation of type List : List | CollectionFlow.cs:210:63:210:69 | access to indexer | $@ | CollectionFlow.cs:210:63:210:69 | access to indexer | access to indexer | +| CollectionFlow.cs:58:20:58:32 | object creation of type List : List | CollectionFlow.cs:58:20:58:32 | object creation of type List : List | CollectionFlow.cs:60:14:60:20 | access to indexer | $@ | CollectionFlow.cs:60:14:60:20 | access to indexer | access to indexer | +| CollectionFlow.cs:58:20:58:32 | object creation of type List : List | CollectionFlow.cs:58:20:58:32 | object creation of type List : List | CollectionFlow.cs:62:14:62:28 | call to method ListFirst | $@ | CollectionFlow.cs:62:14:62:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:58:20:58:32 | object creation of type List : List | CollectionFlow.cs:58:20:58:32 | object creation of type List : List | CollectionFlow.cs:210:63:210:69 | access to indexer | $@ | CollectionFlow.cs:210:63:210:69 | access to indexer | access to indexer | +| CollectionFlow.cs:67:17:67:23 | object creation of type A : A | CollectionFlow.cs:67:17:67:23 | object creation of type A : A | CollectionFlow.cs:69:14:69:20 | access to indexer | $@ | CollectionFlow.cs:69:14:69:20 | access to indexer | access to indexer | +| CollectionFlow.cs:67:17:67:23 | object creation of type A : A | CollectionFlow.cs:67:17:67:23 | object creation of type A : A | CollectionFlow.cs:71:14:71:28 | call to method ListFirst | $@ | CollectionFlow.cs:71:14:71:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:67:17:67:23 | object creation of type A : A | CollectionFlow.cs:67:17:67:23 | object creation of type A : A | CollectionFlow.cs:210:63:210:69 | access to indexer | $@ | CollectionFlow.cs:210:63:210:69 | access to indexer | access to indexer | +| CollectionFlow.cs:68:20:68:38 | object creation of type List : List | CollectionFlow.cs:68:20:68:38 | object creation of type List : List | CollectionFlow.cs:69:14:69:20 | access to indexer | $@ | CollectionFlow.cs:69:14:69:20 | access to indexer | access to indexer | +| CollectionFlow.cs:68:20:68:38 | object creation of type List : List | CollectionFlow.cs:68:20:68:38 | object creation of type List : List | CollectionFlow.cs:71:14:71:28 | call to method ListFirst | $@ | CollectionFlow.cs:71:14:71:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:68:20:68:38 | object creation of type List : List | CollectionFlow.cs:68:20:68:38 | object creation of type List : List | CollectionFlow.cs:210:63:210:69 | access to indexer | $@ | CollectionFlow.cs:210:63:210:69 | access to indexer | access to indexer | +| CollectionFlow.cs:76:20:76:42 | object creation of type List : List | CollectionFlow.cs:76:20:76:42 | object creation of type List : List | CollectionFlow.cs:77:14:77:20 | access to indexer | $@ | CollectionFlow.cs:77:14:77:20 | access to indexer | access to indexer | +| CollectionFlow.cs:76:20:76:42 | object creation of type List : List | CollectionFlow.cs:76:20:76:42 | object creation of type List : List | CollectionFlow.cs:79:14:79:28 | call to method ListFirst | $@ | CollectionFlow.cs:79:14:79:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:76:20:76:42 | object creation of type List : List | CollectionFlow.cs:76:20:76:42 | object creation of type List : List | CollectionFlow.cs:210:63:210:69 | access to indexer | $@ | CollectionFlow.cs:210:63:210:69 | access to indexer | access to indexer | +| CollectionFlow.cs:84:17:84:23 | object creation of type A : A | CollectionFlow.cs:84:17:84:23 | object creation of type A : A | CollectionFlow.cs:87:14:87:20 | access to indexer | $@ | CollectionFlow.cs:87:14:87:20 | access to indexer | access to indexer | +| CollectionFlow.cs:84:17:84:23 | object creation of type A : A | CollectionFlow.cs:84:17:84:23 | object creation of type A : A | CollectionFlow.cs:89:14:89:28 | call to method ListFirst | $@ | CollectionFlow.cs:89:14:89:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:84:17:84:23 | object creation of type A : A | CollectionFlow.cs:84:17:84:23 | object creation of type A : A | CollectionFlow.cs:210:63:210:69 | access to indexer | $@ | CollectionFlow.cs:210:63:210:69 | access to indexer | access to indexer | +| CollectionFlow.cs:85:20:85:32 | object creation of type List : List | CollectionFlow.cs:85:20:85:32 | object creation of type List : List | CollectionFlow.cs:87:14:87:20 | access to indexer | $@ | CollectionFlow.cs:87:14:87:20 | access to indexer | access to indexer | +| CollectionFlow.cs:85:20:85:32 | object creation of type List : List | CollectionFlow.cs:85:20:85:32 | object creation of type List : List | CollectionFlow.cs:89:14:89:28 | call to method ListFirst | $@ | CollectionFlow.cs:89:14:89:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:85:20:85:32 | object creation of type List : List | CollectionFlow.cs:85:20:85:32 | object creation of type List : List | CollectionFlow.cs:210:63:210:69 | access to indexer | $@ | CollectionFlow.cs:210:63:210:69 | access to indexer | access to indexer | +| CollectionFlow.cs:94:20:94:32 | object creation of type List : List | CollectionFlow.cs:94:20:94:32 | object creation of type List : List | CollectionFlow.cs:96:14:96:20 | access to indexer | $@ | CollectionFlow.cs:96:14:96:20 | access to indexer | access to indexer | +| CollectionFlow.cs:94:20:94:32 | object creation of type List : List | CollectionFlow.cs:94:20:94:32 | object creation of type List : List | CollectionFlow.cs:98:14:98:28 | call to method ListFirst | $@ | CollectionFlow.cs:98:14:98:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:94:20:94:32 | object creation of type List : List | CollectionFlow.cs:94:20:94:32 | object creation of type List : List | CollectionFlow.cs:210:63:210:69 | access to indexer | $@ | CollectionFlow.cs:210:63:210:69 | access to indexer | access to indexer | +| CollectionFlow.cs:103:17:103:23 | object creation of type A : A | CollectionFlow.cs:103:17:103:23 | object creation of type A : A | CollectionFlow.cs:106:14:106:20 | access to indexer | $@ | CollectionFlow.cs:106:14:106:20 | access to indexer | access to indexer | +| CollectionFlow.cs:103:17:103:23 | object creation of type A : A | CollectionFlow.cs:103:17:103:23 | object creation of type A : A | CollectionFlow.cs:108:14:108:34 | call to method DictFirstValueA | $@ | CollectionFlow.cs:108:14:108:34 | call to method DictFirstValueA | call to method DictFirstValueA | +| CollectionFlow.cs:103:17:103:23 | object creation of type A : A | CollectionFlow.cs:103:17:103:23 | object creation of type A : A | CollectionFlow.cs:110:14:110:34 | call to method DictFirstValueC | $@ | CollectionFlow.cs:110:14:110:34 | call to method DictFirstValueC | call to method DictFirstValueC | +| CollectionFlow.cs:103:17:103:23 | object creation of type A : A | CollectionFlow.cs:103:17:103:23 | object creation of type A : A | CollectionFlow.cs:212:75:212:81 | access to indexer | $@ | CollectionFlow.cs:212:75:212:81 | access to indexer | access to indexer | +| CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:106:14:106:20 | access to indexer | $@ | CollectionFlow.cs:106:14:106:20 | access to indexer | access to indexer | +| CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:108:14:108:34 | call to method DictFirstValueA | $@ | CollectionFlow.cs:108:14:108:34 | call to method DictFirstValueA | call to method DictFirstValueA | +| CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:110:14:110:34 | call to method DictFirstValueC | $@ | CollectionFlow.cs:110:14:110:34 | call to method DictFirstValueC | call to method DictFirstValueC | +| CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:212:75:212:81 | access to indexer | $@ | CollectionFlow.cs:212:75:212:81 | access to indexer | access to indexer | +| CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:117:14:117:20 | access to indexer | $@ | CollectionFlow.cs:117:14:117:20 | access to indexer | access to indexer | +| CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:119:14:119:34 | call to method DictFirstValueA | $@ | CollectionFlow.cs:119:14:119:34 | call to method DictFirstValueA | call to method DictFirstValueA | +| CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:121:14:121:34 | call to method DictFirstValueC | $@ | CollectionFlow.cs:121:14:121:34 | call to method DictFirstValueC | call to method DictFirstValueC | +| CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:212:75:212:81 | access to indexer | $@ | CollectionFlow.cs:212:75:212:81 | access to indexer | access to indexer | +| CollectionFlow.cs:126:17:126:23 | object creation of type A : A | CollectionFlow.cs:126:17:126:23 | object creation of type A : A | CollectionFlow.cs:128:14:128:20 | access to indexer | $@ | CollectionFlow.cs:128:14:128:20 | access to indexer | access to indexer | +| CollectionFlow.cs:126:17:126:23 | object creation of type A : A | CollectionFlow.cs:126:17:126:23 | object creation of type A : A | CollectionFlow.cs:130:14:130:34 | call to method DictFirstValueA | $@ | CollectionFlow.cs:130:14:130:34 | call to method DictFirstValueA | call to method DictFirstValueA | +| CollectionFlow.cs:126:17:126:23 | object creation of type A : A | CollectionFlow.cs:126:17:126:23 | object creation of type A : A | CollectionFlow.cs:132:14:132:34 | call to method DictFirstValueC | $@ | CollectionFlow.cs:132:14:132:34 | call to method DictFirstValueC | call to method DictFirstValueC | +| CollectionFlow.cs:126:17:126:23 | object creation of type A : A | CollectionFlow.cs:126:17:126:23 | object creation of type A : A | CollectionFlow.cs:212:75:212:81 | access to indexer | $@ | CollectionFlow.cs:212:75:212:81 | access to indexer | access to indexer | +| CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:128:14:128:20 | access to indexer | $@ | CollectionFlow.cs:128:14:128:20 | access to indexer | access to indexer | +| CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:130:14:130:34 | call to method DictFirstValueA | $@ | CollectionFlow.cs:130:14:130:34 | call to method DictFirstValueA | call to method DictFirstValueA | +| CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:132:14:132:34 | call to method DictFirstValueC | $@ | CollectionFlow.cs:132:14:132:34 | call to method DictFirstValueC | call to method DictFirstValueC | +| CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:212:75:212:81 | access to indexer | $@ | CollectionFlow.cs:212:75:212:81 | access to indexer | access to indexer | +| CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:138:14:138:20 | access to indexer | $@ | CollectionFlow.cs:138:14:138:20 | access to indexer | access to indexer | +| CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:140:14:140:34 | call to method DictFirstValueA | $@ | CollectionFlow.cs:140:14:140:34 | call to method DictFirstValueA | call to method DictFirstValueA | +| CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:142:14:142:34 | call to method DictFirstValueC | $@ | CollectionFlow.cs:142:14:142:34 | call to method DictFirstValueC | call to method DictFirstValueC | +| CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:212:75:212:81 | access to indexer | $@ | CollectionFlow.cs:212:75:212:81 | access to indexer | access to indexer | +| CollectionFlow.cs:166:17:166:23 | object creation of type A : A | CollectionFlow.cs:166:17:166:23 | object creation of type A : A | CollectionFlow.cs:169:18:169:18 | access to local variable x | $@ | CollectionFlow.cs:169:18:169:18 | access to local variable x | access to local variable x | +| CollectionFlow.cs:181:17:181:23 | object creation of type A : A | CollectionFlow.cs:181:17:181:23 | object creation of type A : A | CollectionFlow.cs:185:18:185:35 | access to property Current | $@ | CollectionFlow.cs:185:18:185:35 | access to property Current | access to property Current | diff --git a/csharp/ql/test/library-tests/dataflow/arrays/ArrayFlow.ql b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.ql similarity index 100% rename from csharp/ql/test/library-tests/dataflow/arrays/ArrayFlow.ql rename to csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.ql From e186c9ddd190a83f9bd5d1e8b8f355ca4e4cafda Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 20 Apr 2020 09:29:51 +0200 Subject: [PATCH 0202/1298] C#: Update data-flow collection test method names --- .../dataflow/collections/CollectionFlow.cs | 88 ++-- .../collections/CollectionFlow.expected | 464 +++++++++--------- 2 files changed, 277 insertions(+), 275 deletions(-) diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs index 37ae6c6d299..3565ba0b6ea 100644 --- a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs @@ -3,9 +3,11 @@ using System; using System.Collections.Generic; using System.Linq; -public class A +public class CollectionFlow { - public void M1() + public class A { } + + public void ArrayInitializerFlow() { var a = new A(); var @as = new[] { a }; @@ -14,7 +16,7 @@ public class A Sink(First(@as)); // flow } - public void M2(A other) + public void ArrayInitializerNoFlow(A other) { var a = new A(); var @as = new[] { other }; @@ -23,7 +25,7 @@ public class A Sink(First(@as)); // no flow } - public void M3() + public void ArrayAssignmentFlow() { var a = new A(); var @as = new A[1]; @@ -33,7 +35,7 @@ public class A Sink(First(@as)); // flow } - public void M4(A other) + public void ArrayAssignmentNoFlow(A other) { var a = new A(); var @as = new A[1]; @@ -43,7 +45,7 @@ public class A Sink(First(@as)); // no flow } - public void M5() + public void ListAssignmentFlow() { var a = new A(); var list = new List(); @@ -53,7 +55,7 @@ public class A Sink(ListFirst(list)); // flow } - public void M6(A other) + public void ListAssignmentNoFlow(A other) { var list = new List(); list[0] = other; @@ -62,7 +64,7 @@ public class A Sink(ListFirst(list)); // no flow } - public void M7() + public void ListInitializerFlow() { var a = new A(); var list = new List() { a }; @@ -71,7 +73,7 @@ public class A Sink(ListFirst(list)); // flow } - public void M8(A other) + public void ListInitializerNoFlow(A other) { var list = new List() { other }; Sink(list[0]); // no flow @@ -79,7 +81,7 @@ public class A Sink(ListFirst(list)); // no flow } - public void M9() + public void ListAddFlow() { var a = new A(); var list = new List(); @@ -89,7 +91,7 @@ public class A Sink(ListFirst(list)); // flow } - public void M10(A other) + public void ListAddNoFlow(A other) { var list = new List(); list.Add(other); @@ -98,70 +100,70 @@ public class A Sink(ListFirst(list)); // no flow } - public void M11() + public void DictionaryAssignmentFlow() { var a = new A(); var dict = new Dictionary(); dict[0] = a; Sink(dict[0]); // flow SinkDictValue(dict); // flow - Sink(DictFirstValueA(dict)); // flow - Sink(DictFirstValueB(dict)); // flow [MISSING] - Sink(DictFirstValueC(dict)); // flow + Sink(DictIndexZero(dict)); // flow + Sink(DictFirstValue(dict)); // flow [MISSING] + Sink(DictValuesFirst(dict)); // flow } - public void M12(A other) + public void DictionaryAssignmentNoFlow(A other) { var dict = new Dictionary(); dict[0] = other; Sink(dict[0]); // no flow SinkDictValue(dict); // no flow - Sink(DictFirstValueA(dict)); // no flow - Sink(DictFirstValueB(dict)); // no flow - Sink(DictFirstValueC(dict)); // no flow + Sink(DictIndexZero(dict)); // no flow + Sink(DictFirstValue(dict)); // no flow + Sink(DictValuesFirst(dict)); // no flow } - public void M13() + public void DictionaryValueInitializerFlow() { var a = new A(); var dict = new Dictionary() { { 0, a } }; Sink(dict[0]); // flow SinkDictValue(dict); // flow - Sink(DictFirstValueA(dict)); // flow - Sink(DictFirstValueB(dict)); // flow [MISSING] - Sink(DictFirstValueC(dict)); // flow + Sink(DictIndexZero(dict)); // flow + Sink(DictFirstValue(dict)); // flow [MISSING] + Sink(DictValuesFirst(dict)); // flow } - public void M14(A other) + public void DictionaryValueInitializerNoFlow(A other) { var dict = new Dictionary() { { 0, other } }; Sink(dict[0]); // no flow SinkDictValue(dict); // no flow - Sink(DictFirstValueA(dict)); // no flow - Sink(DictFirstValueB(dict)); // no flow - Sink(DictFirstValueC(dict)); // no flow + Sink(DictIndexZero(dict)); // no flow + Sink(DictFirstValue(dict)); // no flow + Sink(DictValuesFirst(dict)); // no flow } - public void M15() + public void DictionaryKeyInitializerFlow() { var a = new A(); var dict = new Dictionary() { { a, 0 } }; Sink(dict.Keys.First()); // flow [MISSING] SinkDictKey(dict); // flow [MISSING] - Sink(DictFirstKeyA(dict)); // flow [MISSING] - Sink(DictFirstKeyB(dict)); // flow [MISSING] + Sink(DictKeysFirst(dict)); // flow [MISSING] + Sink(DictFirstKey(dict)); // flow [MISSING] } - public void M16(A other) + public void DictionaryKeyInitializerNoFlow(A other) { var dict = new Dictionary() { { other, 0 } }; Sink(dict.Keys.First()); // no flow SinkDictKey(dict); // no flow - Sink(DictFirstKeyA(dict)); // no flow - Sink(DictFirstKeyB(dict)); // no flow + Sink(DictKeysFirst(dict)); // no flow + Sink(DictFirstKey(dict)); // no flow } - public void M17() + public void ForeachFlow() { var a = new A(); var @as = new[] { a }; @@ -169,14 +171,14 @@ public class A Sink(x); // flow } - public void M18(A other) + public void ForeachNoFlow(A other) { var @as = new[] { other }; foreach (var x in @as) Sink(x); // no flow } - public void M19() + public void ArrayGetEnumeratorFlow() { var a = new A(); var @as = new[] { a }; @@ -185,7 +187,7 @@ public class A Sink(enumerator.Current); // flow } - public void M20(A other) + public void ArrayGetEnumeratorNoFlow(A other) { var @as = new[] { other }; var enumerator = @as.GetEnumerator(); @@ -193,7 +195,7 @@ public class A Sink(enumerator.Current); // no flow } - public void M21() + public void ListGetEnumeratorFlow() { var a = new A(); var list = new List(); @@ -217,13 +219,13 @@ public class A public static T ListFirst(IList list) => list[0]; - public static T DictFirstValueA(IDictionary dict) => dict[0]; + public static T DictIndexZero(IDictionary dict) => dict[0]; - public static T DictFirstValueB(IDictionary dict) => dict.First().Value; + public static T DictFirstValue(IDictionary dict) => dict.First().Value; - public static T DictFirstValueC(IDictionary dict) => dict.Values.First(); + public static T DictValuesFirst(IDictionary dict) => dict.Values.First(); - public static T DictFirstKeyA(IDictionary dict) => dict.Keys.First(); + public static T DictKeysFirst(IDictionary dict) => dict.Keys.First(); - public static T DictFirstKeyB(IDictionary dict) => dict.First().Key; + public static T DictFirstKey(IDictionary dict) => dict.First().Key; } diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected index d0019ee529e..c6cc298ea94 100644 --- a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected @@ -1,235 +1,235 @@ edges -| CollectionFlow.cs:10:17:10:23 | object creation of type A : A | CollectionFlow.cs:12:14:12:19 | access to array element | -| CollectionFlow.cs:10:17:10:23 | object creation of type A : A | CollectionFlow.cs:13:18:13:20 | access to local variable as : A[] | -| CollectionFlow.cs:10:17:10:23 | object creation of type A : A | CollectionFlow.cs:14:20:14:22 | access to local variable as : A[] | -| CollectionFlow.cs:13:18:13:20 | access to local variable as : A[] | CollectionFlow.cs:208:40:208:41 | ts : A[] | -| CollectionFlow.cs:14:20:14:22 | access to local variable as : A[] | CollectionFlow.cs:14:14:14:23 | call to method First | -| CollectionFlow.cs:28:17:28:23 | object creation of type A : A | CollectionFlow.cs:31:14:31:19 | access to array element | -| CollectionFlow.cs:28:17:28:23 | object creation of type A : A | CollectionFlow.cs:32:18:32:20 | access to local variable as : A[] | -| CollectionFlow.cs:28:17:28:23 | object creation of type A : A | CollectionFlow.cs:33:20:33:22 | access to local variable as : A[] | -| CollectionFlow.cs:32:18:32:20 | access to local variable as : A[] | CollectionFlow.cs:208:40:208:41 | ts : A[] | -| CollectionFlow.cs:33:20:33:22 | access to local variable as : A[] | CollectionFlow.cs:33:14:33:23 | call to method First | -| CollectionFlow.cs:48:17:48:23 | object creation of type A : A | CollectionFlow.cs:51:14:51:20 | access to indexer | -| CollectionFlow.cs:48:17:48:23 | object creation of type A : A | CollectionFlow.cs:52:22:52:25 | access to local variable list : List | -| CollectionFlow.cs:48:17:48:23 | object creation of type A : A | CollectionFlow.cs:53:24:53:27 | access to local variable list : List | -| CollectionFlow.cs:49:20:49:32 | object creation of type List : List | CollectionFlow.cs:51:14:51:20 | access to indexer | -| CollectionFlow.cs:49:20:49:32 | object creation of type List : List | CollectionFlow.cs:52:22:52:25 | access to local variable list : List | -| CollectionFlow.cs:49:20:49:32 | object creation of type List : List | CollectionFlow.cs:53:24:53:27 | access to local variable list : List | -| CollectionFlow.cs:52:22:52:25 | access to local variable list : List | CollectionFlow.cs:210:49:210:52 | list : List | -| CollectionFlow.cs:53:24:53:27 | access to local variable list : List | CollectionFlow.cs:53:14:53:28 | call to method ListFirst | -| CollectionFlow.cs:58:20:58:32 | object creation of type List : List | CollectionFlow.cs:60:14:60:20 | access to indexer | -| CollectionFlow.cs:58:20:58:32 | object creation of type List : List | CollectionFlow.cs:61:22:61:25 | access to local variable list : List | -| CollectionFlow.cs:58:20:58:32 | object creation of type List : List | CollectionFlow.cs:62:24:62:27 | access to local variable list : List | -| CollectionFlow.cs:61:22:61:25 | access to local variable list : List | CollectionFlow.cs:210:49:210:52 | list : List | -| CollectionFlow.cs:62:24:62:27 | access to local variable list : List | CollectionFlow.cs:62:14:62:28 | call to method ListFirst | -| CollectionFlow.cs:67:17:67:23 | object creation of type A : A | CollectionFlow.cs:69:14:69:20 | access to indexer | -| CollectionFlow.cs:67:17:67:23 | object creation of type A : A | CollectionFlow.cs:70:22:70:25 | access to local variable list : List | -| CollectionFlow.cs:67:17:67:23 | object creation of type A : A | CollectionFlow.cs:71:24:71:27 | access to local variable list : List | -| CollectionFlow.cs:68:20:68:38 | object creation of type List : List | CollectionFlow.cs:69:14:69:20 | access to indexer | -| CollectionFlow.cs:68:20:68:38 | object creation of type List : List | CollectionFlow.cs:70:22:70:25 | access to local variable list : List | -| CollectionFlow.cs:68:20:68:38 | object creation of type List : List | CollectionFlow.cs:71:24:71:27 | access to local variable list : List | -| CollectionFlow.cs:70:22:70:25 | access to local variable list : List | CollectionFlow.cs:210:49:210:52 | list : List | -| CollectionFlow.cs:71:24:71:27 | access to local variable list : List | CollectionFlow.cs:71:14:71:28 | call to method ListFirst | -| CollectionFlow.cs:76:20:76:42 | object creation of type List : List | CollectionFlow.cs:77:14:77:20 | access to indexer | -| CollectionFlow.cs:76:20:76:42 | object creation of type List : List | CollectionFlow.cs:78:22:78:25 | access to local variable list : List | -| CollectionFlow.cs:76:20:76:42 | object creation of type List : List | CollectionFlow.cs:79:24:79:27 | access to local variable list : List | -| CollectionFlow.cs:78:22:78:25 | access to local variable list : List | CollectionFlow.cs:210:49:210:52 | list : List | -| CollectionFlow.cs:79:24:79:27 | access to local variable list : List | CollectionFlow.cs:79:14:79:28 | call to method ListFirst | -| CollectionFlow.cs:84:17:84:23 | object creation of type A : A | CollectionFlow.cs:87:14:87:20 | access to indexer | -| CollectionFlow.cs:84:17:84:23 | object creation of type A : A | CollectionFlow.cs:88:22:88:25 | access to local variable list : List | -| CollectionFlow.cs:84:17:84:23 | object creation of type A : A | CollectionFlow.cs:89:24:89:27 | access to local variable list : List | -| CollectionFlow.cs:85:20:85:32 | object creation of type List : List | CollectionFlow.cs:87:14:87:20 | access to indexer | -| CollectionFlow.cs:85:20:85:32 | object creation of type List : List | CollectionFlow.cs:88:22:88:25 | access to local variable list : List | -| CollectionFlow.cs:85:20:85:32 | object creation of type List : List | CollectionFlow.cs:89:24:89:27 | access to local variable list : List | -| CollectionFlow.cs:88:22:88:25 | access to local variable list : List | CollectionFlow.cs:210:49:210:52 | list : List | -| CollectionFlow.cs:89:24:89:27 | access to local variable list : List | CollectionFlow.cs:89:14:89:28 | call to method ListFirst | -| CollectionFlow.cs:94:20:94:32 | object creation of type List : List | CollectionFlow.cs:96:14:96:20 | access to indexer | -| CollectionFlow.cs:94:20:94:32 | object creation of type List : List | CollectionFlow.cs:97:22:97:25 | access to local variable list : List | -| CollectionFlow.cs:94:20:94:32 | object creation of type List : List | CollectionFlow.cs:98:24:98:27 | access to local variable list : List | -| CollectionFlow.cs:97:22:97:25 | access to local variable list : List | CollectionFlow.cs:210:49:210:52 | list : List | -| CollectionFlow.cs:98:24:98:27 | access to local variable list : List | CollectionFlow.cs:98:14:98:28 | call to method ListFirst | -| CollectionFlow.cs:103:17:103:23 | object creation of type A : A | CollectionFlow.cs:106:14:106:20 | access to indexer | -| CollectionFlow.cs:103:17:103:23 | object creation of type A : A | CollectionFlow.cs:107:23:107:26 | access to local variable dict : Dictionary | -| CollectionFlow.cs:103:17:103:23 | object creation of type A : A | CollectionFlow.cs:108:30:108:33 | access to local variable dict : Dictionary | -| CollectionFlow.cs:103:17:103:23 | object creation of type A : A | CollectionFlow.cs:110:30:110:33 | access to local variable dict : Dictionary | -| CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:106:14:106:20 | access to indexer | -| CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:107:23:107:26 | access to local variable dict : Dictionary | -| CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:108:30:108:33 | access to local variable dict : Dictionary | -| CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:110:30:110:33 | access to local variable dict : Dictionary | -| CollectionFlow.cs:107:23:107:26 | access to local variable dict : Dictionary | CollectionFlow.cs:212:61:212:64 | dict : Dictionary | -| CollectionFlow.cs:108:30:108:33 | access to local variable dict : Dictionary | CollectionFlow.cs:108:14:108:34 | call to method DictFirstValueA | -| CollectionFlow.cs:110:30:110:33 | access to local variable dict : Dictionary | CollectionFlow.cs:110:14:110:34 | call to method DictFirstValueC | -| CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:117:14:117:20 | access to indexer | -| CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:118:23:118:26 | access to local variable dict : Dictionary | -| CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:119:30:119:33 | access to local variable dict : Dictionary | -| CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:121:30:121:33 | access to local variable dict : Dictionary | -| CollectionFlow.cs:118:23:118:26 | access to local variable dict : Dictionary | CollectionFlow.cs:212:61:212:64 | dict : Dictionary | -| CollectionFlow.cs:119:30:119:33 | access to local variable dict : Dictionary | CollectionFlow.cs:119:14:119:34 | call to method DictFirstValueA | -| CollectionFlow.cs:121:30:121:33 | access to local variable dict : Dictionary | CollectionFlow.cs:121:14:121:34 | call to method DictFirstValueC | -| CollectionFlow.cs:126:17:126:23 | object creation of type A : A | CollectionFlow.cs:128:14:128:20 | access to indexer | -| CollectionFlow.cs:126:17:126:23 | object creation of type A : A | CollectionFlow.cs:129:23:129:26 | access to local variable dict : Dictionary | -| CollectionFlow.cs:126:17:126:23 | object creation of type A : A | CollectionFlow.cs:130:30:130:33 | access to local variable dict : Dictionary | -| CollectionFlow.cs:126:17:126:23 | object creation of type A : A | CollectionFlow.cs:132:30:132:33 | access to local variable dict : Dictionary | -| CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:128:14:128:20 | access to indexer | -| CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:129:23:129:26 | access to local variable dict : Dictionary | -| CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:130:30:130:33 | access to local variable dict : Dictionary | -| CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:132:30:132:33 | access to local variable dict : Dictionary | -| CollectionFlow.cs:129:23:129:26 | access to local variable dict : Dictionary | CollectionFlow.cs:212:61:212:64 | dict : Dictionary | -| CollectionFlow.cs:130:30:130:33 | access to local variable dict : Dictionary | CollectionFlow.cs:130:14:130:34 | call to method DictFirstValueA | -| CollectionFlow.cs:132:30:132:33 | access to local variable dict : Dictionary | CollectionFlow.cs:132:14:132:34 | call to method DictFirstValueC | -| CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:138:14:138:20 | access to indexer | -| CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:139:23:139:26 | access to local variable dict : Dictionary | -| CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:140:30:140:33 | access to local variable dict : Dictionary | -| CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:142:30:142:33 | access to local variable dict : Dictionary | -| CollectionFlow.cs:139:23:139:26 | access to local variable dict : Dictionary | CollectionFlow.cs:212:61:212:64 | dict : Dictionary | -| CollectionFlow.cs:140:30:140:33 | access to local variable dict : Dictionary | CollectionFlow.cs:140:14:140:34 | call to method DictFirstValueA | -| CollectionFlow.cs:142:30:142:33 | access to local variable dict : Dictionary | CollectionFlow.cs:142:14:142:34 | call to method DictFirstValueC | -| CollectionFlow.cs:166:17:166:23 | object creation of type A : A | CollectionFlow.cs:169:18:169:18 | access to local variable x | -| CollectionFlow.cs:181:17:181:23 | object creation of type A : A | CollectionFlow.cs:185:18:185:35 | access to property Current | -| CollectionFlow.cs:208:40:208:41 | ts : A[] | CollectionFlow.cs:208:52:208:56 | access to array element | -| CollectionFlow.cs:210:49:210:52 | list : List | CollectionFlow.cs:210:63:210:69 | access to indexer | -| CollectionFlow.cs:212:61:212:64 | dict : Dictionary | CollectionFlow.cs:212:75:212:81 | access to indexer | +| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:14:14:14:19 | access to array element | +| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:15:18:15:20 | access to local variable as : A[] | +| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:16:20:16:22 | access to local variable as : A[] | +| CollectionFlow.cs:15:18:15:20 | access to local variable as : A[] | CollectionFlow.cs:210:40:210:41 | ts : A[] | +| CollectionFlow.cs:16:20:16:22 | access to local variable as : A[] | CollectionFlow.cs:16:14:16:23 | call to method First | +| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:33:14:33:19 | access to array element | +| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:34:18:34:20 | access to local variable as : A[] | +| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:35:20:35:22 | access to local variable as : A[] | +| CollectionFlow.cs:34:18:34:20 | access to local variable as : A[] | CollectionFlow.cs:210:40:210:41 | ts : A[] | +| CollectionFlow.cs:35:20:35:22 | access to local variable as : A[] | CollectionFlow.cs:35:14:35:23 | call to method First | +| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:53:14:53:20 | access to indexer | +| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:54:22:54:25 | access to local variable list : List | +| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:55:24:55:27 | access to local variable list : List | +| CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:53:14:53:20 | access to indexer | +| CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:54:22:54:25 | access to local variable list : List | +| CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:55:24:55:27 | access to local variable list : List | +| CollectionFlow.cs:54:22:54:25 | access to local variable list : List | CollectionFlow.cs:212:49:212:52 | list : List | +| CollectionFlow.cs:55:24:55:27 | access to local variable list : List | CollectionFlow.cs:55:14:55:28 | call to method ListFirst | +| CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:62:14:62:20 | access to indexer | +| CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:63:22:63:25 | access to local variable list : List | +| CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:64:24:64:27 | access to local variable list : List | +| CollectionFlow.cs:63:22:63:25 | access to local variable list : List | CollectionFlow.cs:212:49:212:52 | list : List | +| CollectionFlow.cs:64:24:64:27 | access to local variable list : List | CollectionFlow.cs:64:14:64:28 | call to method ListFirst | +| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:71:14:71:20 | access to indexer | +| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:72:22:72:25 | access to local variable list : List | +| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:73:24:73:27 | access to local variable list : List | +| CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:71:14:71:20 | access to indexer | +| CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:72:22:72:25 | access to local variable list : List | +| CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:73:24:73:27 | access to local variable list : List | +| CollectionFlow.cs:72:22:72:25 | access to local variable list : List | CollectionFlow.cs:212:49:212:52 | list : List | +| CollectionFlow.cs:73:24:73:27 | access to local variable list : List | CollectionFlow.cs:73:14:73:28 | call to method ListFirst | +| CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:79:14:79:20 | access to indexer | +| CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:80:22:80:25 | access to local variable list : List | +| CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:81:24:81:27 | access to local variable list : List | +| CollectionFlow.cs:80:22:80:25 | access to local variable list : List | CollectionFlow.cs:212:49:212:52 | list : List | +| CollectionFlow.cs:81:24:81:27 | access to local variable list : List | CollectionFlow.cs:81:14:81:28 | call to method ListFirst | +| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:89:14:89:20 | access to indexer | +| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:90:22:90:25 | access to local variable list : List | +| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:91:24:91:27 | access to local variable list : List | +| CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:89:14:89:20 | access to indexer | +| CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:90:22:90:25 | access to local variable list : List | +| CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:91:24:91:27 | access to local variable list : List | +| CollectionFlow.cs:90:22:90:25 | access to local variable list : List | CollectionFlow.cs:212:49:212:52 | list : List | +| CollectionFlow.cs:91:24:91:27 | access to local variable list : List | CollectionFlow.cs:91:14:91:28 | call to method ListFirst | +| CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:98:14:98:20 | access to indexer | +| CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:99:22:99:25 | access to local variable list : List | +| CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:100:24:100:27 | access to local variable list : List | +| CollectionFlow.cs:99:22:99:25 | access to local variable list : List | CollectionFlow.cs:212:49:212:52 | list : List | +| CollectionFlow.cs:100:24:100:27 | access to local variable list : List | CollectionFlow.cs:100:14:100:28 | call to method ListFirst | +| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:108:14:108:20 | access to indexer | +| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:109:23:109:26 | access to local variable dict : Dictionary | +| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:110:28:110:31 | access to local variable dict : Dictionary | +| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:112:30:112:33 | access to local variable dict : Dictionary | +| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:108:14:108:20 | access to indexer | +| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:109:23:109:26 | access to local variable dict : Dictionary | +| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:110:28:110:31 | access to local variable dict : Dictionary | +| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:112:30:112:33 | access to local variable dict : Dictionary | +| CollectionFlow.cs:109:23:109:26 | access to local variable dict : Dictionary | CollectionFlow.cs:214:61:214:64 | dict : Dictionary | +| CollectionFlow.cs:110:28:110:31 | access to local variable dict : Dictionary | CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | +| CollectionFlow.cs:112:30:112:33 | access to local variable dict : Dictionary | CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | +| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:119:14:119:20 | access to indexer | +| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:120:23:120:26 | access to local variable dict : Dictionary | +| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:121:28:121:31 | access to local variable dict : Dictionary | +| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:123:30:123:33 | access to local variable dict : Dictionary | +| CollectionFlow.cs:120:23:120:26 | access to local variable dict : Dictionary | CollectionFlow.cs:214:61:214:64 | dict : Dictionary | +| CollectionFlow.cs:121:28:121:31 | access to local variable dict : Dictionary | CollectionFlow.cs:121:14:121:32 | call to method DictIndexZero | +| CollectionFlow.cs:123:30:123:33 | access to local variable dict : Dictionary | CollectionFlow.cs:123:14:123:34 | call to method DictValuesFirst | +| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:130:14:130:20 | access to indexer | +| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:131:23:131:26 | access to local variable dict : Dictionary | +| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:132:28:132:31 | access to local variable dict : Dictionary | +| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:134:30:134:33 | access to local variable dict : Dictionary | +| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:130:14:130:20 | access to indexer | +| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:131:23:131:26 | access to local variable dict : Dictionary | +| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:132:28:132:31 | access to local variable dict : Dictionary | +| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:134:30:134:33 | access to local variable dict : Dictionary | +| CollectionFlow.cs:131:23:131:26 | access to local variable dict : Dictionary | CollectionFlow.cs:214:61:214:64 | dict : Dictionary | +| CollectionFlow.cs:132:28:132:31 | access to local variable dict : Dictionary | CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | +| CollectionFlow.cs:134:30:134:33 | access to local variable dict : Dictionary | CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | +| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:140:14:140:20 | access to indexer | +| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:141:23:141:26 | access to local variable dict : Dictionary | +| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:142:28:142:31 | access to local variable dict : Dictionary | +| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:144:30:144:33 | access to local variable dict : Dictionary | +| CollectionFlow.cs:141:23:141:26 | access to local variable dict : Dictionary | CollectionFlow.cs:214:61:214:64 | dict : Dictionary | +| CollectionFlow.cs:142:28:142:31 | access to local variable dict : Dictionary | CollectionFlow.cs:142:14:142:32 | call to method DictIndexZero | +| CollectionFlow.cs:144:30:144:33 | access to local variable dict : Dictionary | CollectionFlow.cs:144:14:144:34 | call to method DictValuesFirst | +| CollectionFlow.cs:168:17:168:23 | object creation of type A : A | CollectionFlow.cs:171:18:171:18 | access to local variable x | +| CollectionFlow.cs:183:17:183:23 | object creation of type A : A | CollectionFlow.cs:187:18:187:35 | access to property Current | +| CollectionFlow.cs:210:40:210:41 | ts : A[] | CollectionFlow.cs:210:52:210:56 | access to array element | +| CollectionFlow.cs:212:49:212:52 | list : List | CollectionFlow.cs:212:63:212:69 | access to indexer | +| CollectionFlow.cs:214:61:214:64 | dict : Dictionary | CollectionFlow.cs:214:75:214:81 | access to indexer | nodes -| CollectionFlow.cs:10:17:10:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:12:14:12:19 | access to array element | semmle.label | access to array element | -| CollectionFlow.cs:13:18:13:20 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | -| CollectionFlow.cs:14:14:14:23 | call to method First | semmle.label | call to method First | -| CollectionFlow.cs:14:20:14:22 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | -| CollectionFlow.cs:28:17:28:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:31:14:31:19 | access to array element | semmle.label | access to array element | -| CollectionFlow.cs:32:18:32:20 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | -| CollectionFlow.cs:33:14:33:23 | call to method First | semmle.label | call to method First | -| CollectionFlow.cs:33:20:33:22 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | -| CollectionFlow.cs:48:17:48:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:49:20:49:32 | object creation of type List : List | semmle.label | object creation of type List : List | -| CollectionFlow.cs:51:14:51:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:52:22:52:25 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:53:14:53:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:53:24:53:27 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:58:20:58:32 | object creation of type List : List | semmle.label | object creation of type List : List | -| CollectionFlow.cs:60:14:60:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:61:22:61:25 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:62:14:62:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:62:24:62:27 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:67:17:67:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:68:20:68:38 | object creation of type List : List | semmle.label | object creation of type List : List | -| CollectionFlow.cs:69:14:69:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:70:22:70:25 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:71:14:71:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:71:24:71:27 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:76:20:76:42 | object creation of type List : List | semmle.label | object creation of type List : List | -| CollectionFlow.cs:77:14:77:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:78:22:78:25 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:79:14:79:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:79:24:79:27 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:84:17:84:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:85:20:85:32 | object creation of type List : List | semmle.label | object creation of type List : List | -| CollectionFlow.cs:87:14:87:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:88:22:88:25 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:89:14:89:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:89:24:89:27 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:94:20:94:32 | object creation of type List : List | semmle.label | object creation of type List : List | -| CollectionFlow.cs:96:14:96:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:97:22:97:25 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:98:14:98:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:98:24:98:27 | access to local variable list : List | semmle.label | access to local variable list : List | -| CollectionFlow.cs:103:17:103:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | -| CollectionFlow.cs:106:14:106:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:107:23:107:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:108:14:108:34 | call to method DictFirstValueA | semmle.label | call to method DictFirstValueA | -| CollectionFlow.cs:108:30:108:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:110:14:110:34 | call to method DictFirstValueC | semmle.label | call to method DictFirstValueC | -| CollectionFlow.cs:110:30:110:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | -| CollectionFlow.cs:117:14:117:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:118:23:118:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:119:14:119:34 | call to method DictFirstValueA | semmle.label | call to method DictFirstValueA | -| CollectionFlow.cs:119:30:119:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:121:14:121:34 | call to method DictFirstValueC | semmle.label | call to method DictFirstValueC | -| CollectionFlow.cs:121:30:121:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:126:17:126:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | -| CollectionFlow.cs:128:14:128:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:129:23:129:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:130:14:130:34 | call to method DictFirstValueA | semmle.label | call to method DictFirstValueA | -| CollectionFlow.cs:130:30:130:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:132:14:132:34 | call to method DictFirstValueC | semmle.label | call to method DictFirstValueC | -| CollectionFlow.cs:132:30:132:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | -| CollectionFlow.cs:138:14:138:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:139:23:139:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:140:14:140:34 | call to method DictFirstValueA | semmle.label | call to method DictFirstValueA | -| CollectionFlow.cs:140:30:140:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:142:14:142:34 | call to method DictFirstValueC | semmle.label | call to method DictFirstValueC | -| CollectionFlow.cs:142:30:142:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | -| CollectionFlow.cs:166:17:166:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:169:18:169:18 | access to local variable x | semmle.label | access to local variable x | -| CollectionFlow.cs:181:17:181:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:185:18:185:35 | access to property Current | semmle.label | access to property Current | -| CollectionFlow.cs:208:40:208:41 | ts : A[] | semmle.label | ts : A[] | -| CollectionFlow.cs:208:52:208:56 | access to array element | semmle.label | access to array element | -| CollectionFlow.cs:210:49:210:52 | list : List | semmle.label | list : List | -| CollectionFlow.cs:210:63:210:69 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:212:61:212:64 | dict : Dictionary | semmle.label | dict : Dictionary | -| CollectionFlow.cs:212:75:212:81 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:14:14:14:19 | access to array element | semmle.label | access to array element | +| CollectionFlow.cs:15:18:15:20 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | +| CollectionFlow.cs:16:14:16:23 | call to method First | semmle.label | call to method First | +| CollectionFlow.cs:16:20:16:22 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | +| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:33:14:33:19 | access to array element | semmle.label | access to array element | +| CollectionFlow.cs:34:18:34:20 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | +| CollectionFlow.cs:35:14:35:23 | call to method First | semmle.label | call to method First | +| CollectionFlow.cs:35:20:35:22 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | +| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:51:20:51:32 | object creation of type List : List | semmle.label | object creation of type List : List | +| CollectionFlow.cs:53:14:53:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:54:22:54:25 | access to local variable list : List | semmle.label | access to local variable list : List | +| CollectionFlow.cs:55:14:55:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| CollectionFlow.cs:55:24:55:27 | access to local variable list : List | semmle.label | access to local variable list : List | +| CollectionFlow.cs:60:20:60:32 | object creation of type List : List | semmle.label | object creation of type List : List | +| CollectionFlow.cs:62:14:62:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:63:22:63:25 | access to local variable list : List | semmle.label | access to local variable list : List | +| CollectionFlow.cs:64:14:64:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| CollectionFlow.cs:64:24:64:27 | access to local variable list : List | semmle.label | access to local variable list : List | +| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:70:20:70:38 | object creation of type List : List | semmle.label | object creation of type List : List | +| CollectionFlow.cs:71:14:71:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:72:22:72:25 | access to local variable list : List | semmle.label | access to local variable list : List | +| CollectionFlow.cs:73:14:73:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| CollectionFlow.cs:73:24:73:27 | access to local variable list : List | semmle.label | access to local variable list : List | +| CollectionFlow.cs:78:20:78:42 | object creation of type List : List | semmle.label | object creation of type List : List | +| CollectionFlow.cs:79:14:79:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:80:22:80:25 | access to local variable list : List | semmle.label | access to local variable list : List | +| CollectionFlow.cs:81:14:81:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| CollectionFlow.cs:81:24:81:27 | access to local variable list : List | semmle.label | access to local variable list : List | +| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:87:20:87:32 | object creation of type List : List | semmle.label | object creation of type List : List | +| CollectionFlow.cs:89:14:89:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:90:22:90:25 | access to local variable list : List | semmle.label | access to local variable list : List | +| CollectionFlow.cs:91:14:91:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| CollectionFlow.cs:91:24:91:27 | access to local variable list : List | semmle.label | access to local variable list : List | +| CollectionFlow.cs:96:20:96:32 | object creation of type List : List | semmle.label | object creation of type List : List | +| CollectionFlow.cs:98:14:98:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:99:22:99:25 | access to local variable list : List | semmle.label | access to local variable list : List | +| CollectionFlow.cs:100:14:100:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| CollectionFlow.cs:100:24:100:27 | access to local variable list : List | semmle.label | access to local variable list : List | +| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | +| CollectionFlow.cs:108:14:108:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:109:23:109:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | +| CollectionFlow.cs:110:28:110:31 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | +| CollectionFlow.cs:112:30:112:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | +| CollectionFlow.cs:119:14:119:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:120:23:120:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| CollectionFlow.cs:121:14:121:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | +| CollectionFlow.cs:121:28:121:31 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| CollectionFlow.cs:123:14:123:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | +| CollectionFlow.cs:123:30:123:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | +| CollectionFlow.cs:130:14:130:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:131:23:131:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | +| CollectionFlow.cs:132:28:132:31 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | +| CollectionFlow.cs:134:30:134:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | semmle.label | object creation of type Dictionary : Dictionary | +| CollectionFlow.cs:140:14:140:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:141:23:141:26 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| CollectionFlow.cs:142:14:142:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | +| CollectionFlow.cs:142:28:142:31 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| CollectionFlow.cs:144:14:144:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | +| CollectionFlow.cs:144:30:144:33 | access to local variable dict : Dictionary | semmle.label | access to local variable dict : Dictionary | +| CollectionFlow.cs:168:17:168:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:171:18:171:18 | access to local variable x | semmle.label | access to local variable x | +| CollectionFlow.cs:183:17:183:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:187:18:187:35 | access to property Current | semmle.label | access to property Current | +| CollectionFlow.cs:210:40:210:41 | ts : A[] | semmle.label | ts : A[] | +| CollectionFlow.cs:210:52:210:56 | access to array element | semmle.label | access to array element | +| CollectionFlow.cs:212:49:212:52 | list : List | semmle.label | list : List | +| CollectionFlow.cs:212:63:212:69 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:214:61:214:64 | dict : Dictionary | semmle.label | dict : Dictionary | +| CollectionFlow.cs:214:75:214:81 | access to indexer | semmle.label | access to indexer | #select -| CollectionFlow.cs:10:17:10:23 | object creation of type A : A | CollectionFlow.cs:10:17:10:23 | object creation of type A : A | CollectionFlow.cs:12:14:12:19 | access to array element | $@ | CollectionFlow.cs:12:14:12:19 | access to array element | access to array element | -| CollectionFlow.cs:10:17:10:23 | object creation of type A : A | CollectionFlow.cs:10:17:10:23 | object creation of type A : A | CollectionFlow.cs:14:14:14:23 | call to method First | $@ | CollectionFlow.cs:14:14:14:23 | call to method First | call to method First | -| CollectionFlow.cs:10:17:10:23 | object creation of type A : A | CollectionFlow.cs:10:17:10:23 | object creation of type A : A | CollectionFlow.cs:208:52:208:56 | access to array element | $@ | CollectionFlow.cs:208:52:208:56 | access to array element | access to array element | -| CollectionFlow.cs:28:17:28:23 | object creation of type A : A | CollectionFlow.cs:28:17:28:23 | object creation of type A : A | CollectionFlow.cs:31:14:31:19 | access to array element | $@ | CollectionFlow.cs:31:14:31:19 | access to array element | access to array element | -| CollectionFlow.cs:28:17:28:23 | object creation of type A : A | CollectionFlow.cs:28:17:28:23 | object creation of type A : A | CollectionFlow.cs:33:14:33:23 | call to method First | $@ | CollectionFlow.cs:33:14:33:23 | call to method First | call to method First | -| CollectionFlow.cs:28:17:28:23 | object creation of type A : A | CollectionFlow.cs:28:17:28:23 | object creation of type A : A | CollectionFlow.cs:208:52:208:56 | access to array element | $@ | CollectionFlow.cs:208:52:208:56 | access to array element | access to array element | -| CollectionFlow.cs:48:17:48:23 | object creation of type A : A | CollectionFlow.cs:48:17:48:23 | object creation of type A : A | CollectionFlow.cs:51:14:51:20 | access to indexer | $@ | CollectionFlow.cs:51:14:51:20 | access to indexer | access to indexer | -| CollectionFlow.cs:48:17:48:23 | object creation of type A : A | CollectionFlow.cs:48:17:48:23 | object creation of type A : A | CollectionFlow.cs:53:14:53:28 | call to method ListFirst | $@ | CollectionFlow.cs:53:14:53:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:48:17:48:23 | object creation of type A : A | CollectionFlow.cs:48:17:48:23 | object creation of type A : A | CollectionFlow.cs:210:63:210:69 | access to indexer | $@ | CollectionFlow.cs:210:63:210:69 | access to indexer | access to indexer | -| CollectionFlow.cs:49:20:49:32 | object creation of type List : List | CollectionFlow.cs:49:20:49:32 | object creation of type List : List | CollectionFlow.cs:51:14:51:20 | access to indexer | $@ | CollectionFlow.cs:51:14:51:20 | access to indexer | access to indexer | -| CollectionFlow.cs:49:20:49:32 | object creation of type List : List | CollectionFlow.cs:49:20:49:32 | object creation of type List : List | CollectionFlow.cs:53:14:53:28 | call to method ListFirst | $@ | CollectionFlow.cs:53:14:53:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:49:20:49:32 | object creation of type List : List | CollectionFlow.cs:49:20:49:32 | object creation of type List : List | CollectionFlow.cs:210:63:210:69 | access to indexer | $@ | CollectionFlow.cs:210:63:210:69 | access to indexer | access to indexer | -| CollectionFlow.cs:58:20:58:32 | object creation of type List : List | CollectionFlow.cs:58:20:58:32 | object creation of type List : List | CollectionFlow.cs:60:14:60:20 | access to indexer | $@ | CollectionFlow.cs:60:14:60:20 | access to indexer | access to indexer | -| CollectionFlow.cs:58:20:58:32 | object creation of type List : List | CollectionFlow.cs:58:20:58:32 | object creation of type List : List | CollectionFlow.cs:62:14:62:28 | call to method ListFirst | $@ | CollectionFlow.cs:62:14:62:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:58:20:58:32 | object creation of type List : List | CollectionFlow.cs:58:20:58:32 | object creation of type List : List | CollectionFlow.cs:210:63:210:69 | access to indexer | $@ | CollectionFlow.cs:210:63:210:69 | access to indexer | access to indexer | -| CollectionFlow.cs:67:17:67:23 | object creation of type A : A | CollectionFlow.cs:67:17:67:23 | object creation of type A : A | CollectionFlow.cs:69:14:69:20 | access to indexer | $@ | CollectionFlow.cs:69:14:69:20 | access to indexer | access to indexer | -| CollectionFlow.cs:67:17:67:23 | object creation of type A : A | CollectionFlow.cs:67:17:67:23 | object creation of type A : A | CollectionFlow.cs:71:14:71:28 | call to method ListFirst | $@ | CollectionFlow.cs:71:14:71:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:67:17:67:23 | object creation of type A : A | CollectionFlow.cs:67:17:67:23 | object creation of type A : A | CollectionFlow.cs:210:63:210:69 | access to indexer | $@ | CollectionFlow.cs:210:63:210:69 | access to indexer | access to indexer | -| CollectionFlow.cs:68:20:68:38 | object creation of type List : List | CollectionFlow.cs:68:20:68:38 | object creation of type List : List | CollectionFlow.cs:69:14:69:20 | access to indexer | $@ | CollectionFlow.cs:69:14:69:20 | access to indexer | access to indexer | -| CollectionFlow.cs:68:20:68:38 | object creation of type List : List | CollectionFlow.cs:68:20:68:38 | object creation of type List : List | CollectionFlow.cs:71:14:71:28 | call to method ListFirst | $@ | CollectionFlow.cs:71:14:71:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:68:20:68:38 | object creation of type List : List | CollectionFlow.cs:68:20:68:38 | object creation of type List : List | CollectionFlow.cs:210:63:210:69 | access to indexer | $@ | CollectionFlow.cs:210:63:210:69 | access to indexer | access to indexer | -| CollectionFlow.cs:76:20:76:42 | object creation of type List : List | CollectionFlow.cs:76:20:76:42 | object creation of type List : List | CollectionFlow.cs:77:14:77:20 | access to indexer | $@ | CollectionFlow.cs:77:14:77:20 | access to indexer | access to indexer | -| CollectionFlow.cs:76:20:76:42 | object creation of type List : List | CollectionFlow.cs:76:20:76:42 | object creation of type List : List | CollectionFlow.cs:79:14:79:28 | call to method ListFirst | $@ | CollectionFlow.cs:79:14:79:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:76:20:76:42 | object creation of type List : List | CollectionFlow.cs:76:20:76:42 | object creation of type List : List | CollectionFlow.cs:210:63:210:69 | access to indexer | $@ | CollectionFlow.cs:210:63:210:69 | access to indexer | access to indexer | -| CollectionFlow.cs:84:17:84:23 | object creation of type A : A | CollectionFlow.cs:84:17:84:23 | object creation of type A : A | CollectionFlow.cs:87:14:87:20 | access to indexer | $@ | CollectionFlow.cs:87:14:87:20 | access to indexer | access to indexer | -| CollectionFlow.cs:84:17:84:23 | object creation of type A : A | CollectionFlow.cs:84:17:84:23 | object creation of type A : A | CollectionFlow.cs:89:14:89:28 | call to method ListFirst | $@ | CollectionFlow.cs:89:14:89:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:84:17:84:23 | object creation of type A : A | CollectionFlow.cs:84:17:84:23 | object creation of type A : A | CollectionFlow.cs:210:63:210:69 | access to indexer | $@ | CollectionFlow.cs:210:63:210:69 | access to indexer | access to indexer | -| CollectionFlow.cs:85:20:85:32 | object creation of type List : List | CollectionFlow.cs:85:20:85:32 | object creation of type List : List | CollectionFlow.cs:87:14:87:20 | access to indexer | $@ | CollectionFlow.cs:87:14:87:20 | access to indexer | access to indexer | -| CollectionFlow.cs:85:20:85:32 | object creation of type List : List | CollectionFlow.cs:85:20:85:32 | object creation of type List : List | CollectionFlow.cs:89:14:89:28 | call to method ListFirst | $@ | CollectionFlow.cs:89:14:89:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:85:20:85:32 | object creation of type List : List | CollectionFlow.cs:85:20:85:32 | object creation of type List : List | CollectionFlow.cs:210:63:210:69 | access to indexer | $@ | CollectionFlow.cs:210:63:210:69 | access to indexer | access to indexer | -| CollectionFlow.cs:94:20:94:32 | object creation of type List : List | CollectionFlow.cs:94:20:94:32 | object creation of type List : List | CollectionFlow.cs:96:14:96:20 | access to indexer | $@ | CollectionFlow.cs:96:14:96:20 | access to indexer | access to indexer | -| CollectionFlow.cs:94:20:94:32 | object creation of type List : List | CollectionFlow.cs:94:20:94:32 | object creation of type List : List | CollectionFlow.cs:98:14:98:28 | call to method ListFirst | $@ | CollectionFlow.cs:98:14:98:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:94:20:94:32 | object creation of type List : List | CollectionFlow.cs:94:20:94:32 | object creation of type List : List | CollectionFlow.cs:210:63:210:69 | access to indexer | $@ | CollectionFlow.cs:210:63:210:69 | access to indexer | access to indexer | -| CollectionFlow.cs:103:17:103:23 | object creation of type A : A | CollectionFlow.cs:103:17:103:23 | object creation of type A : A | CollectionFlow.cs:106:14:106:20 | access to indexer | $@ | CollectionFlow.cs:106:14:106:20 | access to indexer | access to indexer | -| CollectionFlow.cs:103:17:103:23 | object creation of type A : A | CollectionFlow.cs:103:17:103:23 | object creation of type A : A | CollectionFlow.cs:108:14:108:34 | call to method DictFirstValueA | $@ | CollectionFlow.cs:108:14:108:34 | call to method DictFirstValueA | call to method DictFirstValueA | -| CollectionFlow.cs:103:17:103:23 | object creation of type A : A | CollectionFlow.cs:103:17:103:23 | object creation of type A : A | CollectionFlow.cs:110:14:110:34 | call to method DictFirstValueC | $@ | CollectionFlow.cs:110:14:110:34 | call to method DictFirstValueC | call to method DictFirstValueC | -| CollectionFlow.cs:103:17:103:23 | object creation of type A : A | CollectionFlow.cs:103:17:103:23 | object creation of type A : A | CollectionFlow.cs:212:75:212:81 | access to indexer | $@ | CollectionFlow.cs:212:75:212:81 | access to indexer | access to indexer | -| CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:106:14:106:20 | access to indexer | $@ | CollectionFlow.cs:106:14:106:20 | access to indexer | access to indexer | -| CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:108:14:108:34 | call to method DictFirstValueA | $@ | CollectionFlow.cs:108:14:108:34 | call to method DictFirstValueA | call to method DictFirstValueA | -| CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:110:14:110:34 | call to method DictFirstValueC | $@ | CollectionFlow.cs:110:14:110:34 | call to method DictFirstValueC | call to method DictFirstValueC | -| CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:104:20:104:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:212:75:212:81 | access to indexer | $@ | CollectionFlow.cs:212:75:212:81 | access to indexer | access to indexer | -| CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:117:14:117:20 | access to indexer | $@ | CollectionFlow.cs:117:14:117:20 | access to indexer | access to indexer | -| CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:119:14:119:34 | call to method DictFirstValueA | $@ | CollectionFlow.cs:119:14:119:34 | call to method DictFirstValueA | call to method DictFirstValueA | -| CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:121:14:121:34 | call to method DictFirstValueC | $@ | CollectionFlow.cs:121:14:121:34 | call to method DictFirstValueC | call to method DictFirstValueC | -| CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:115:20:115:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:212:75:212:81 | access to indexer | $@ | CollectionFlow.cs:212:75:212:81 | access to indexer | access to indexer | -| CollectionFlow.cs:126:17:126:23 | object creation of type A : A | CollectionFlow.cs:126:17:126:23 | object creation of type A : A | CollectionFlow.cs:128:14:128:20 | access to indexer | $@ | CollectionFlow.cs:128:14:128:20 | access to indexer | access to indexer | -| CollectionFlow.cs:126:17:126:23 | object creation of type A : A | CollectionFlow.cs:126:17:126:23 | object creation of type A : A | CollectionFlow.cs:130:14:130:34 | call to method DictFirstValueA | $@ | CollectionFlow.cs:130:14:130:34 | call to method DictFirstValueA | call to method DictFirstValueA | -| CollectionFlow.cs:126:17:126:23 | object creation of type A : A | CollectionFlow.cs:126:17:126:23 | object creation of type A : A | CollectionFlow.cs:132:14:132:34 | call to method DictFirstValueC | $@ | CollectionFlow.cs:132:14:132:34 | call to method DictFirstValueC | call to method DictFirstValueC | -| CollectionFlow.cs:126:17:126:23 | object creation of type A : A | CollectionFlow.cs:126:17:126:23 | object creation of type A : A | CollectionFlow.cs:212:75:212:81 | access to indexer | $@ | CollectionFlow.cs:212:75:212:81 | access to indexer | access to indexer | -| CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:128:14:128:20 | access to indexer | $@ | CollectionFlow.cs:128:14:128:20 | access to indexer | access to indexer | -| CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:130:14:130:34 | call to method DictFirstValueA | $@ | CollectionFlow.cs:130:14:130:34 | call to method DictFirstValueA | call to method DictFirstValueA | -| CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:132:14:132:34 | call to method DictFirstValueC | $@ | CollectionFlow.cs:132:14:132:34 | call to method DictFirstValueC | call to method DictFirstValueC | -| CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:127:20:127:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:212:75:212:81 | access to indexer | $@ | CollectionFlow.cs:212:75:212:81 | access to indexer | access to indexer | -| CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:138:14:138:20 | access to indexer | $@ | CollectionFlow.cs:138:14:138:20 | access to indexer | access to indexer | -| CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:140:14:140:34 | call to method DictFirstValueA | $@ | CollectionFlow.cs:140:14:140:34 | call to method DictFirstValueA | call to method DictFirstValueA | -| CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:142:14:142:34 | call to method DictFirstValueC | $@ | CollectionFlow.cs:142:14:142:34 | call to method DictFirstValueC | call to method DictFirstValueC | -| CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:137:20:137:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:212:75:212:81 | access to indexer | $@ | CollectionFlow.cs:212:75:212:81 | access to indexer | access to indexer | -| CollectionFlow.cs:166:17:166:23 | object creation of type A : A | CollectionFlow.cs:166:17:166:23 | object creation of type A : A | CollectionFlow.cs:169:18:169:18 | access to local variable x | $@ | CollectionFlow.cs:169:18:169:18 | access to local variable x | access to local variable x | -| CollectionFlow.cs:181:17:181:23 | object creation of type A : A | CollectionFlow.cs:181:17:181:23 | object creation of type A : A | CollectionFlow.cs:185:18:185:35 | access to property Current | $@ | CollectionFlow.cs:185:18:185:35 | access to property Current | access to property Current | +| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:14:14:14:19 | access to array element | $@ | CollectionFlow.cs:14:14:14:19 | access to array element | access to array element | +| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:16:14:16:23 | call to method First | $@ | CollectionFlow.cs:16:14:16:23 | call to method First | call to method First | +| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:210:52:210:56 | access to array element | $@ | CollectionFlow.cs:210:52:210:56 | access to array element | access to array element | +| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:33:14:33:19 | access to array element | $@ | CollectionFlow.cs:33:14:33:19 | access to array element | access to array element | +| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:35:14:35:23 | call to method First | $@ | CollectionFlow.cs:35:14:35:23 | call to method First | call to method First | +| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:210:52:210:56 | access to array element | $@ | CollectionFlow.cs:210:52:210:56 | access to array element | access to array element | +| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:53:14:53:20 | access to indexer | $@ | CollectionFlow.cs:53:14:53:20 | access to indexer | access to indexer | +| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:55:14:55:28 | call to method ListFirst | $@ | CollectionFlow.cs:55:14:55:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | +| CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:53:14:53:20 | access to indexer | $@ | CollectionFlow.cs:53:14:53:20 | access to indexer | access to indexer | +| CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:55:14:55:28 | call to method ListFirst | $@ | CollectionFlow.cs:55:14:55:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:51:20:51:32 | object creation of type List : List | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | +| CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:62:14:62:20 | access to indexer | $@ | CollectionFlow.cs:62:14:62:20 | access to indexer | access to indexer | +| CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:64:14:64:28 | call to method ListFirst | $@ | CollectionFlow.cs:64:14:64:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:60:20:60:32 | object creation of type List : List | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | +| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:71:14:71:20 | access to indexer | $@ | CollectionFlow.cs:71:14:71:20 | access to indexer | access to indexer | +| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:73:14:73:28 | call to method ListFirst | $@ | CollectionFlow.cs:73:14:73:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | +| CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:71:14:71:20 | access to indexer | $@ | CollectionFlow.cs:71:14:71:20 | access to indexer | access to indexer | +| CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:73:14:73:28 | call to method ListFirst | $@ | CollectionFlow.cs:73:14:73:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:70:20:70:38 | object creation of type List : List | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | +| CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:79:14:79:20 | access to indexer | $@ | CollectionFlow.cs:79:14:79:20 | access to indexer | access to indexer | +| CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:81:14:81:28 | call to method ListFirst | $@ | CollectionFlow.cs:81:14:81:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:78:20:78:42 | object creation of type List : List | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | +| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:89:14:89:20 | access to indexer | $@ | CollectionFlow.cs:89:14:89:20 | access to indexer | access to indexer | +| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:91:14:91:28 | call to method ListFirst | $@ | CollectionFlow.cs:91:14:91:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | +| CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:89:14:89:20 | access to indexer | $@ | CollectionFlow.cs:89:14:89:20 | access to indexer | access to indexer | +| CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:91:14:91:28 | call to method ListFirst | $@ | CollectionFlow.cs:91:14:91:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:87:20:87:32 | object creation of type List : List | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | +| CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:98:14:98:20 | access to indexer | $@ | CollectionFlow.cs:98:14:98:20 | access to indexer | access to indexer | +| CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:100:14:100:28 | call to method ListFirst | $@ | CollectionFlow.cs:100:14:100:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:96:20:96:32 | object creation of type List : List | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | +| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:108:14:108:20 | access to indexer | $@ | CollectionFlow.cs:108:14:108:20 | access to indexer | access to indexer | +| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | call to method DictIndexZero | +| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | call to method DictValuesFirst | +| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer | +| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:108:14:108:20 | access to indexer | $@ | CollectionFlow.cs:108:14:108:20 | access to indexer | access to indexer | +| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | call to method DictIndexZero | +| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | call to method DictValuesFirst | +| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer | +| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:119:14:119:20 | access to indexer | $@ | CollectionFlow.cs:119:14:119:20 | access to indexer | access to indexer | +| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:121:14:121:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:121:14:121:32 | call to method DictIndexZero | call to method DictIndexZero | +| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:123:14:123:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:123:14:123:34 | call to method DictValuesFirst | call to method DictValuesFirst | +| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer | +| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:130:14:130:20 | access to indexer | $@ | CollectionFlow.cs:130:14:130:20 | access to indexer | access to indexer | +| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | call to method DictIndexZero | +| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | call to method DictValuesFirst | +| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer | +| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:130:14:130:20 | access to indexer | $@ | CollectionFlow.cs:130:14:130:20 | access to indexer | access to indexer | +| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | call to method DictIndexZero | +| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | call to method DictValuesFirst | +| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer | +| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:140:14:140:20 | access to indexer | $@ | CollectionFlow.cs:140:14:140:20 | access to indexer | access to indexer | +| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:142:14:142:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:142:14:142:32 | call to method DictIndexZero | call to method DictIndexZero | +| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:144:14:144:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:144:14:144:34 | call to method DictValuesFirst | call to method DictValuesFirst | +| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary : Dictionary | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer | +| CollectionFlow.cs:168:17:168:23 | object creation of type A : A | CollectionFlow.cs:168:17:168:23 | object creation of type A : A | CollectionFlow.cs:171:18:171:18 | access to local variable x | $@ | CollectionFlow.cs:171:18:171:18 | access to local variable x | access to local variable x | +| CollectionFlow.cs:183:17:183:23 | object creation of type A : A | CollectionFlow.cs:183:17:183:23 | object creation of type A : A | CollectionFlow.cs:187:18:187:35 | access to property Current | $@ | CollectionFlow.cs:187:18:187:35 | access to property Current | access to property Current | From c713ba7bfec53276bc18f34f74212fbd60808149 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 20 Apr 2020 10:51:42 +0200 Subject: [PATCH 0203/1298] fix typo --- javascript/ql/src/Expressions/MisspelledVariableName.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/Expressions/MisspelledVariableName.ql b/javascript/ql/src/Expressions/MisspelledVariableName.ql index 9eeeb288134..b6f0ad88e3e 100644 --- a/javascript/ql/src/Expressions/MisspelledVariableName.ql +++ b/javascript/ql/src/Expressions/MisspelledVariableName.ql @@ -29,7 +29,7 @@ bindingset[name] int globalAccesses(string name) { result = count(GlobalVarAccess acc | acc.getName() = name) } /** - * Holds if our heuristic says that the local variable `lvd` seems to be a misspelling of the global variable `gvd`. + * Holds if our heuristic says that the local variable `lvd` seems to be a misspelling of the global variable `gva`. * Otherwise the global variable is likely the misspelling. */ predicate globalIsLikelyCorrect(GlobalVarAccess gva, VarDecl lvd) { From e0cd595d54abcc5e6c122e85e9d2bdb9d1e95cc8 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 20 Apr 2020 11:46:10 +0200 Subject: [PATCH 0204/1298] C++: Reduce intermediate tuple counts --- .../code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index ac0d7fa6ce3..4a87ed50313 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 @@ -417,8 +417,6 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction()) } -private predicate hasSize(Type t, int size) { t.getSize() = size } - cached private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction iTo) { iTo.(CopyInstruction).getSourceValue() = iFrom @@ -467,11 +465,12 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = chi ) or - iTo.(CopyInstruction).getSourceValueOperand().getAnyDef() = iFrom and - exists(Class c, int size | + iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = iFrom.(StoreInstruction) and + exists(Class c, Type t | c = iTo.getResultType() and - hasSize(c, size) and - hasSize(iFrom.getResultType(), size) + t = iFrom.getResultType() and + c.getAField().getUnspecifiedType() = t and + c.getSize() = t.getSize() ) or // Flow through modeled functions From 2d3e42e6d66aacf8c20609fae964040fa5278b2f Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 20 Apr 2020 11:50:46 +0200 Subject: [PATCH 0205/1298] update qhelp for xss-through-dom Co-Authored-By: Asger F --- javascript/ql/src/Security/CWE-079/XssThroughDom.qhelp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/javascript/ql/src/Security/CWE-079/XssThroughDom.qhelp b/javascript/ql/src/Security/CWE-079/XssThroughDom.qhelp index 297e3739fee..ca99672f4a5 100644 --- a/javascript/ql/src/Security/CWE-079/XssThroughDom.qhelp +++ b/javascript/ql/src/Security/CWE-079/XssThroughDom.qhelp @@ -5,8 +5,7 @@

    -Writing text from a webpage to the same webpage without properly sanitizing the -input first, might allow for a cross-site scripting vulnerability. +Extracting text from a DOM node and interpreting it as HTML can lead to a cross-site scripting vulnerability.

    A webpage with this vulnerability unescapes an otherwise sanitized text, From bccc27f1e7b3bfe181794a0cd68f24cecc278bfe Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Sun, 19 Apr 2020 10:28:24 +0100 Subject: [PATCH 0206/1298] JS: Rephrase flowsTo to avoid redundant SourceNode::Range check --- .../semmle/javascript/dataflow/Sources.qll | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Sources.qll b/javascript/ql/src/semmle/javascript/dataflow/Sources.qll index 1fe799eac85..131f94f1ef6 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Sources.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Sources.qll @@ -39,11 +39,7 @@ class SourceNode extends DataFlow::Node { * Holds if this node flows into `sink` in zero or more local (that is, * intra-procedural) steps. */ - cached - predicate flowsTo(DataFlow::Node sink) { - sink = this or - flowsTo(sink.getAPredecessor()) - } + predicate flowsTo(DataFlow::Node sink) { hasLocalSource(sink, this) } /** * Holds if this node flows into `sink` in zero or more local (that is, @@ -195,6 +191,24 @@ class SourceNode extends DataFlow::Node { } } +/** + * Holds if `source` is a `SourceNode` that can reach `sink` via local flow steps. + * + * The slightly backwards parametering ordering is to force correct indexing. + */ +cached +private predicate hasLocalSource(DataFlow::Node sink, DataFlow::Node source) { + // Declaring `source` to be a `SourceNode` currently causes a redundant check in the + // recursive case, so instead we check it explicitly here. + source = sink and + source instanceof DataFlow::SourceNode + or + exists(DataFlow::Node mid | + hasLocalSource(mid, source) and + DataFlow::localFlowStep(mid, sink) + ) +} + module SourceNode { /** * A data flow node that should be considered a source node. From ead916702a7f71b8e3d33c2361bd06b0077d8d66 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Mon, 20 Apr 2020 09:32:35 +0100 Subject: [PATCH 0207/1298] C#: Take nullability into account when creating symbol entities. Otherwise, an entity with the wrong (cached) nullability could be created. --- .../Entities/Accessor.cs | 2 +- .../Entities/Constructor.cs | 2 +- .../Entities/Conversion.cs | 2 +- .../Entities/Destructor.cs | 2 +- .../Entities/Event.cs | 2 +- .../Entities/EventAccessor.cs | 2 +- .../Entities/Field.cs | 2 +- .../Entities/Indexer.cs | 2 +- .../Entities/LocalFunction.cs | 2 +- .../Entities/LocalVariable.cs | 2 +- .../Entities/OrdinaryMethod.cs | 2 +- .../Entities/Property.cs | 2 +- .../Entities/Types/ArrayType.cs | 2 +- .../Entities/Types/DynamicType.cs | 2 +- .../Entities/Types/NamedType.cs | 2 +- .../Entities/Types/PointerType.cs | 2 +- .../Entities/Types/TupleType.cs | 2 +- .../Entities/Types/Type.cs | 8 +++++ .../Entities/Types/TypeParameter.cs | 2 +- .../Entities/UserOperator.cs | 2 +- csharp/extractor/Semmle.Extraction/Context.cs | 33 ++++++++++++++++--- csharp/extractor/Semmle.Extraction/Entity.cs | 13 ++++++++ .../csharp8/NullableRefTypes.expected | 2 +- 23 files changed, 70 insertions(+), 24 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Accessor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Accessor.cs index 98c021c8a6d..cc713b5ad2f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Accessor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Accessor.cs @@ -77,7 +77,7 @@ namespace Semmle.Extraction.CSharp.Entities } public new static Accessor Create(Context cx, IMethodSymbol symbol) => - AccessorFactory.Instance.CreateEntity(cx, symbol); + AccessorFactory.Instance.CreateEntityFromSymbol(cx, symbol); class AccessorFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs index 298f838cfb9..a9baacbf728 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs @@ -104,7 +104,7 @@ namespace Semmle.Extraction.CSharp.Entities { case MethodKind.StaticConstructor: case MethodKind.Constructor: - return ConstructorFactory.Instance.CreateEntity(cx, constructor); + return ConstructorFactory.Instance.CreateEntityFromSymbol(cx, constructor); default: throw new InternalError(constructor, "Attempt to create a Constructor from a symbol that isn't a constructor"); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Conversion.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Conversion.cs index e365ca53ae0..98758fb773f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Conversion.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Conversion.cs @@ -11,7 +11,7 @@ namespace Semmle.Extraction.CSharp.Entities : base(cx, init) { } public new static Conversion Create(Context cx, IMethodSymbol symbol) => - ConversionFactory.Instance.CreateEntity(cx, symbol); + ConversionFactory.Instance.CreateEntityFromSymbol(cx, symbol); public override Microsoft.CodeAnalysis.Location ReportingLocation { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Destructor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Destructor.cs index 33f3a330f94..65557b16b67 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Destructor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Destructor.cs @@ -24,7 +24,7 @@ namespace Semmle.Extraction.CSharp.Entities } public new static Destructor Create(Context cx, IMethodSymbol symbol) => - DestructorFactory.Instance.CreateEntity(cx, symbol); + DestructorFactory.Instance.CreateEntityFromSymbol(cx, symbol); class DestructorFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Event.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Event.cs index 224c81b9524..59f937a6331 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Event.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Event.cs @@ -60,7 +60,7 @@ namespace Semmle.Extraction.CSharp.Entities TypeMention.Create(Context, syntaxType, this, type); } - public static Event Create(Context cx, IEventSymbol symbol) => EventFactory.Instance.CreateEntity(cx, symbol); + public static Event Create(Context cx, IEventSymbol symbol) => EventFactory.Instance.CreateEntityFromSymbol(cx, symbol); class EventFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/EventAccessor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/EventAccessor.cs index 7dc0a4dfcff..da858b689dc 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/EventAccessor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/EventAccessor.cs @@ -53,7 +53,7 @@ namespace Semmle.Extraction.CSharp.Entities } public new static EventAccessor Create(Context cx, IMethodSymbol symbol) => - EventAccessorFactory.Instance.CreateEntity(cx, symbol); + EventAccessorFactory.Instance.CreateEntityFromSymbol(cx, symbol); class EventAccessorFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs index 7ae4572cd7d..f126b7ff52f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs @@ -18,7 +18,7 @@ namespace Semmle.Extraction.CSharp.Entities type = new Lazy(() => Entities.Type.Create(cx, symbol.GetAnnotatedType())); } - public static Field Create(Context cx, IFieldSymbol field) => FieldFactory.Instance.CreateEntity(cx, field); + public static Field Create(Context cx, IFieldSymbol field) => FieldFactory.Instance.CreateEntityFromSymbol(cx, field); // Do not populate backing fields. // Populate Tuple fields. diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Indexer.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Indexer.cs index b9ece3d8c8e..af07c41dd6b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Indexer.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Indexer.cs @@ -71,7 +71,7 @@ namespace Semmle.Extraction.CSharp.Entities TypeMention.Create(Context, syntax.Type, this, type); } - public static new Indexer Create(Context cx, IPropertySymbol prop) => IndexerFactory.Instance.CreateEntity(cx, prop); + public static new Indexer Create(Context cx, IPropertySymbol prop) => IndexerFactory.Instance.CreateEntityFromSymbol(cx, prop); public override void WriteId(TextWriter trapFile) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs index e570802ab3d..8b90f6905dd 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs @@ -22,7 +22,7 @@ namespace Semmle.Extraction.CSharp.Entities trapFile.Write('*'); } - public static new LocalFunction Create(Context cx, IMethodSymbol field) => LocalFunctionFactory.Instance.CreateEntity(cx, field); + public static new LocalFunction Create(Context cx, IMethodSymbol field) => LocalFunctionFactory.Instance.CreateEntityFromSymbol(cx, field); class LocalFunctionFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalVariable.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalVariable.cs index 6d0f14a014e..02d89d08a2f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalVariable.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalVariable.cs @@ -43,7 +43,7 @@ namespace Semmle.Extraction.CSharp.Entities public static LocalVariable Create(Context cx, ISymbol local) { - return LocalVariableFactory.Instance.CreateEntity(cx, local); + return LocalVariableFactory.Instance.CreateEntityFromSymbol(cx, local); } void DefineConstantValue(TextWriter trapFile) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs index cb12918e72e..74e7de35a16 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs @@ -49,7 +49,7 @@ namespace Semmle.Extraction.CSharp.Entities ExtractCompilerGenerated(trapFile); } - public new static OrdinaryMethod Create(Context cx, IMethodSymbol method) => OrdinaryMethodFactory.Instance.CreateEntity(cx, method); + public new static OrdinaryMethod Create(Context cx, IMethodSymbol method) => OrdinaryMethodFactory.Instance.CreateEntityFromSymbol(cx, method); class OrdinaryMethodFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs index e5e2cc8ab26..05ff97db805 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs @@ -113,7 +113,7 @@ namespace Semmle.Extraction.CSharp.Entities { bool isIndexer = prop.IsIndexer || prop.Parameters.Any(); - return isIndexer ? Indexer.Create(cx, prop) : PropertyFactory.Instance.CreateEntity(cx, prop); + return isIndexer ? Indexer.Create(cx, prop) : PropertyFactory.Instance.CreateEntityFromSymbol(cx, prop); } public void VisitDeclaration(Context cx, PropertyDeclarationSyntax p) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/ArrayType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/ArrayType.cs index c4a79a7764b..9e211660344 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/ArrayType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/ArrayType.cs @@ -36,7 +36,7 @@ namespace Semmle.Extraction.CSharp.Entities trapFile.Write(";type"); } - public static ArrayType Create(Context cx, IArrayTypeSymbol symbol) => ArrayTypeFactory.Instance.CreateEntity(cx, symbol); + public static ArrayType Create(Context cx, IArrayTypeSymbol symbol) => ArrayTypeFactory.Instance.CreateEntityFromSymbol(cx, symbol); class ArrayTypeFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/DynamicType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/DynamicType.cs index f5b6bf36c44..bfaba1cff85 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/DynamicType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/DynamicType.cs @@ -9,7 +9,7 @@ namespace Semmle.Extraction.CSharp.Entities DynamicType(Context cx, IDynamicTypeSymbol init) : base(cx, init) { } - public static DynamicType Create(Context cx, IDynamicTypeSymbol type) => DynamicTypeFactory.Instance.CreateEntity(cx, type); + public static DynamicType Create(Context cx, IDynamicTypeSymbol type) => DynamicTypeFactory.Instance.CreateEntityFromSymbol(cx, type); public override Microsoft.CodeAnalysis.Location ReportingLocation => Context.Compilation.ObjectType.Locations.FirstOrDefault(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs index 25145520aee..20b7bf12ca8 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs @@ -17,7 +17,7 @@ namespace Semmle.Extraction.CSharp.Entities typeArgumentsLazy = new Lazy(() => symbol.TypeArguments.Select(t => Create(cx, t)).ToArray()); } - public static NamedType Create(Context cx, INamedTypeSymbol type) => NamedTypeFactory.Instance.CreateEntity(cx, type); + public static NamedType Create(Context cx, INamedTypeSymbol type) => NamedTypeFactory.Instance.CreateEntityFromSymbol(cx, type); public override bool NeedsPopulation => base.NeedsPopulation || symbol.TypeKind == TypeKind.Error; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/PointerType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/PointerType.cs index db8b5ff8c23..229666e6260 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/PointerType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/PointerType.cs @@ -29,7 +29,7 @@ namespace Semmle.Extraction.CSharp.Entities public Type PointedAtType { get; private set; } - public static PointerType Create(Context cx, IPointerTypeSymbol symbol) => PointerTypeFactory.Instance.CreateEntity(cx, symbol); + public static PointerType Create(Context cx, IPointerTypeSymbol symbol) => PointerTypeFactory.Instance.CreateEntityFromSymbol(cx, symbol); class PointerTypeFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs index b7e38fd88f4..ae9d3139a5c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs @@ -13,7 +13,7 @@ namespace Semmle.Extraction.CSharp.Entities /// class TupleType : Type { - public static TupleType Create(Context cx, INamedTypeSymbol type) => TupleTypeFactory.Instance.CreateEntity(cx, type); + public static TupleType Create(Context cx, INamedTypeSymbol type) => TupleTypeFactory.Instance.CreateEntityFromSymbol(cx, type); class TupleTypeFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs index 7d9f5e3651e..857d3def945 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs @@ -324,6 +324,14 @@ namespace Semmle.Extraction.CSharp.Entities } public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; + + public override bool Equals(object obj) + { + var other = obj as Type; + return other?.GetType() == GetType() && SymbolEqualityComparer.IncludeNullability.Equals(other.symbol, symbol); + } + + public override int GetHashCode() => SymbolEqualityComparer.IncludeNullability.GetHashCode(symbol); } abstract class Type : Type where T : ITypeSymbol diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs index 2fdb8cd3a83..2c7c6373143 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs @@ -88,7 +88,7 @@ namespace Semmle.Extraction.CSharp.Entities } static public TypeParameter Create(Context cx, ITypeParameterSymbol p) => - TypeParameterFactory.Instance.CreateEntity(cx, p); + TypeParameterFactory.Instance.CreateEntityFromSymbol(cx, p); ///

    /// The variance of this type parameter. diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs index 9c94058af1f..a66ae7cb1e8 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs @@ -190,7 +190,7 @@ namespace Semmle.Extraction.CSharp.Entities return result; } - public new static UserOperator Create(Context cx, IMethodSymbol symbol) => UserOperatorFactory.Instance.CreateEntity(cx, symbol); + public new static UserOperator Create(Context cx, IMethodSymbol symbol) => UserOperatorFactory.Instance.CreateEntityFromSymbol(cx, symbol); class UserOperatorFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction/Context.cs b/csharp/extractor/Semmle.Extraction/Context.cs index 918642f198d..7d860dabc69 100644 --- a/csharp/extractor/Semmle.Extraction/Context.cs +++ b/csharp/extractor/Semmle.Extraction/Context.cs @@ -51,7 +51,18 @@ namespace Semmle.Extraction /// The new/existing entity. public Entity CreateEntity(ICachedEntityFactory factory, Type init) where Entity : ICachedEntity { - return init == null ? CreateEntity2(factory, init) : CreateNonNullEntity(factory, init); + return init == null ? CreateEntity2(factory, init) : CreateNonNullEntity(factory, init, objectEntityCache); + } + + /// + /// Creates a new entity using the factory. + /// + /// The entity factory. + /// The initializer for the entity. + /// The new/existing entity. + public Entity CreateEntityFromSymbol(ICachedEntityFactory factory, Type init) where Entity : ICachedEntity + { + return init == null ? CreateEntity2(factory, init) : CreateNonNullEntity(factory, init, symbolEntityCache); } // A recursion guard against writing to the trap file whilst writing an id to the trap file. @@ -136,8 +147,12 @@ namespace Semmle.Extraction public Label GetNewLabel() => new Label(GetNewId()); private Entity CreateNonNullEntity(ICachedEntityFactory factory, Type init) where Entity : ICachedEntity + => CreateNonNullEntity(factory, init, objectEntityCache); + + + private Entity CreateNonNullEntity(ICachedEntityFactory factory, Type init, IDictionary dictionary) where Entity : ICachedEntity { - if (objectEntityCache.TryGetValue(init, out var cached)) + if (dictionary.TryGetValue(init, out var cached)) return (Entity)cached; using (StackGuard) @@ -146,7 +161,7 @@ namespace Semmle.Extraction var entity = factory.Create(this, init); entity.Label = label; - objectEntityCache[init] = entity; + dictionary[init] = entity; DefineLabel(entity, TrapWriter.Writer, Extractor); if (entity.NeedsPopulation) @@ -200,7 +215,17 @@ namespace Semmle.Extraction #if DEBUG_LABELS readonly Dictionary idLabelCache = new Dictionary(); #endif - readonly Dictionary objectEntityCache = new Dictionary(); + class SymbolComparer : IEqualityComparer + { + IEqualityComparer comparer = SymbolEqualityComparer.IncludeNullability; + + bool IEqualityComparer.Equals(object x, object y) => comparer.Equals((ISymbol)x, (ISymbol)y); + + int IEqualityComparer.GetHashCode(object obj) => comparer.GetHashCode((ISymbol)obj); + } + + readonly IDictionary objectEntityCache = new Dictionary(); + readonly IDictionary symbolEntityCache = new Dictionary(10000, new SymbolComparer()); readonly Dictionary entityLabelCache = new Dictionary(); readonly HashSet